rs@uunet.UU.NET (Rich Salz) (08/04/87)
Submitted-by: Dick Grune <dick@cs.vu.nl> Posting-number: Volume 10, Issue 89 Archive-name: magtapetools/Part02 : --------------------------- cut here -------------------------- PATH=/bin:/usr/bin echo Extracting \a\n\s\i\.\h sed 's/^X//' > \a\n\s\i\.\h << '+ END-OF-FILE '\a\n\s\i\.\h X/* This file is part of the magtape handling package MAG. X Written by Dick Grune, Vrije Universiteit, Amsterdam. X*/ X X#include <stdio.h> X Xextern char *strcpy(); X X#define NL '\n' X#define TAB '\t' X#define SP ' ' X#define EOS '\0' X X#define TRUE 1 X#define FALSE 0 X X#define MAXSTR 128 X X/* X * It is tempting to use structs for the declaration of the label data X * structures, access the fields through selectors and let the C-compiler X * do the offset calculation. There are, however, two problems: X * 1. alignment is different on different machines (VAX vs. PDP11), X * 2. according to the book the fields may even be arranged in inverse X * order. X * So structs are out and defines are in. X * A field is implemented as a pair: an address and a length. X */ X X/* the general fields */ X#define Whole(p) &(p)[0], sizeof (p) X#define Labidf(p) &(p)[0], 4 X X/* the VOL1 label */ X#define Volidf(p) &(p)[4], 6 X#define Volacc(p) &(p)[10], 1 X#define Sp1(p) &(p)[11], 26 X#define Ownidf(p) &(p)[37], 14 X#define Sp2(p) &(p)[51], 28 X#define Labvers(p) &(p)[79], 1 X X/* dates */ X#define Sp(p) &(p)[0], 1 X#define Date(p) &(p)[1], 5 X#define Yr(p) &(p)[1], 2 X#define Yd(p) &(p)[3], 3 X X/* the HDR1 label */ X#define Fileidf(p) &(p)[4], 17 X#define Filesetidf(p) &(p)[21], 6 X#define Filsecnum(p) &(p)[27], 4 X#define Filseqnum(p) &(p)[31], 4 X#define Gennum(p) &(p)[35], 4 X#define Genversnum(p) &(p)[39], 2 X#define Creatdate(p) &(p)[41], 6 X#define Expirdate(p) &(p)[47], 6 X#define Fileacc(p) &(p)[53], 1 X#define Blkcount(p) &(p)[54], 6 X#define Syscode(p) &(p)[60], 13 X#define Sp3(p) &(p)[73], 7 X X/* the HDR2 label */ X#define Recformat(p) &(p)[4], 1 X#define Blklength(p) &(p)[5], 5 X#define Reclength(p) &(p)[10], 5 X#define Syssoftw(p) &(p)[15], 35 X#define Bufoffset(p) &(p)[50], 2 X#define Sp4(p) &(p)[52], 28 X X/* the USRn label */ X#define Contents(p) &(p)[4], 76 X X Xextern int unit; Xextern char *nmdns; Xextern TPFILE *tf; X X#define ASK_NO 0 /* use default and check */ X#define ASK_YES 1 /* ask and check */ X#define ASK_SUG 2 /* suggest default and check */ X#define ASK_ERR 3 /* ask again and check */ X X/* Macros to define an additional control structure to handle X interactive input, under the presence of user errors. X*/ X#define inmood(md) {int mood = md; for (;;mood=ASK_ERR) X#define iferr(cond) if(cond){print_loc(); X#define enderr continue;} X#define endmood break;} X Xextern char *sps2txt(), *str2txt(), *expl2str(), *tty_line(), *tty_str(); Xextern char *enq_str(), *fld2str(), *char2str(); Xextern int enq_int(), isascstr(), fld2int(); Xextern fld2fld(), str2fld(), prf_s(), errors(); X Xstruct format { X char type; X int (*checkpar)(); X int (*cpblk)(); X}; X Xextern struct format formats[]; Xextern struct format *format_of_type(); X Xextern char filename[MAXSTR]; Xextern FILE *file; Xextern int filseqnum; Xextern int filsecnum; Xextern char rectype[1]; Xextern struct format *recformat; Xextern int blklength; Xextern int reclength; Xextern int bufoffset; Xextern int reccount; Xextern int blkcount; X Xextern char VOL1buf[80]; Xextern char HDR1buf[80]; Xextern char HDR2buf[80]; + END-OF-FILE ansi.h chmod 'u=rw,g=r,o=r' \a\n\s\i\.\h set `sum \a\n\s\i\.\h` sum=$1 case $sum in 43328) :;; *) echo 'Bad sum in '\a\n\s\i\.\h >&2 esac echo Extracting \e\t\o\a\.\h sed 's/^X//' > \e\t\o\a\.\h << '+ END-OF-FILE '\e\t\o\a\.\h X/* This file is part of the magtape handling package MAG. X Written by Dick Grune, Vrije Universiteit, Amsterdam. X*/ X Xextern char _etoa[]; /* from etoa.c */ X X#define ebc2asc(c) (_etoa[(c)&0377]) + END-OF-FILE etoa.h chmod 'u=rw,g=r,o=r' \e\t\o\a\.\h set `sum \e\t\o\a\.\h` sum=$1 case $sum in 11080) :;; *) echo 'Bad sum in '\e\t\o\a\.\h >&2 esac echo Extracting \o\p\t\i\o\n\s\.\h sed 's/^X//' > \o\p\t\i\o\n\s\.\h << '+ END-OF-FILE '\o\p\t\i\o\n\s\.\h X/* This file is part of the magtape handling package MAG. X Written by Dick Grune, Vrije Universiteit, Amsterdam. X*/ X X/* Having a chunk out of a switch statement as a separate include X file is unusual, but this file does implement a conceptual unit: X the handling of the standard command line options for describing X a generalized magtape. See mag.1. X X This include file assumes X aux.h to be included X tp.h idem X uses and updates X argc as supplied by main() X argv idem X sets X unit the unit number X nmdns file name or density X and jumps to X Lbad on bad command line parameters X*/ X X default: X goto Lbad; X case 'c': /* character device */ X unit = TP_CDEV; X if (argc < 2) X goto Lbad; X nmdns = argv[1]; X argc--, argv++; X break; X case 'f': /* tape image */ X unit = TP_IMAG; X if (argc < 2) X goto Lbad; X nmdns = argv[1]; X argc--, argv++; X break; X case 'h': /* high density */ X nmdns = TP_DENH; X break; X case 'l': /* low density */ X nmdns = TP_DENL; X break; X case 'm': /* unit number (real tape unit) */ X if (argc < 2) X goto Lbad; X if (!is_digit(argv[1][0])) X goto Lbad; X unit = atoi(argv[1]); X argc--, argv++; X break; + END-OF-FILE options.h chmod 'u=rw,g=r,o=r' \o\p\t\i\o\n\s\.\h set `sum \o\p\t\i\o\n\s\.\h` sum=$1 case $sum in 18446) :;; *) echo 'Bad sum in '\o\p\t\i\o\n\s\.\h >&2 esac echo Extracting \a\n\s\i\.\c sed 's/^X//' > \a\n\s\i\.\c << '+ END-OF-FILE '\a\n\s\i\.\c X/* This file is part of the magtape handling package MAG. X Written by Dick Grune, Vrije Universiteit, Amsterdam. X*/ X X#include "aux.h" X#include "tp.h" X#include "ansi.h" X Xextern char *sprintf(); X Xint unit = 0; Xchar *nmdns = TP_DENN; XTPFILE *tf = NULL; X Xchar filename[MAXSTR]; XFILE *file = NULL; Xint filseqnum = 0; Xint filsecnum = 1; Xchar rectype[1] = 'F'; Xstruct format *recformat; Xint blklength = 1920; Xint reclength = 80; Xint bufoffset = 0; Xint reccount; Xint blkcount; X Xchar VOL1buf[80]; Xchar HDR1buf[80]; Xchar HDR2buf[80]; X Xchar * Xsps2txt(p) { X return p == 0 ? "<empty>" : p == 1 ? "<space>" : "<spaces>"; X} X Xchar * Xstr2txt(s) X char *s; X{ X int p = 0; X X while (s[p] != EOS) { X if (s[p] != SP) X return s; X p++; X } X return sps2txt(p); X} X X/* An expl(anation) is an explanatory string which contains the name of the X * object being explained as the first item between ` and ' . The expl may X * contain one %s which is replaced by the default (string) value. X */ X Xchar * /* transient */ Xexpl2str(expl) X char *expl; X{ X static char str[MAXSTR]; X char *nm = expl, cnt = 0; X X while (*nm != EOS && *nm != '`') { X nm++; X } X nm++; X while (*nm != EOS && *nm != '\'') { X if (cnt < MAXSTR-1) X str[cnt++] = *nm; X nm++; X } X str[cnt] = EOS; X return str; X} X Xchar * /* transient */ Xtty_line() { X static char ans[MAXSTR]; X int cnt = 0; X int ch; X X while ((ch = getchar()) != NL) { X if (ch == EOF) X errors("\n*** No interaction!!!"); X if (cnt < MAXSTR-1) X ans[cnt++] = ch; X } X ans[cnt] = EOS; X return ans; X} X Xchar * /* transient */ Xtty_str(prompt, expl, md, def) X char *prompt, *expl, md, *def; X{ X static char conversation = FALSE; X char *str; X int err = 0; X X if (!conversation) { X prf_s("\n\ X I shall have to ask some questions; to get more information,\n\ X answer a question with a single question mark (?).\n\n", ""); X conversation = TRUE; X } X while (err < 3) { X printf(prompt, expl2str(expl)); X str= tty_line(); X if (strcmp(str, "?") == 0) { X printf("\n"); X prf_s(expl, def); X printf("\n"); X } X else X if (strlen(str) > 0) X return str; X else X if (md == ASK_SUG) X return NULL; X else { X printf("I do need an answer!\n"); X err++; X } X } X errors("\nSorry"); X return str; X} X Xchar * /* transient */ Xenq_str(expl, md, def) X char *expl, *def; X{ X char *str; X X switch (md) { X case ASK_NO: X str = def; X break; X case ASK_YES: X print_loc(); X str = tty_str("Please type your %s: ", expl, md, def); X break; X case ASK_SUG: X print_loc(); X printf("Default %s: ", expl2str(expl)); X prf_s("%s\n", str2txt(def)); X str = tty_str("Please type a new %s, or press RETURN: ", X expl, md, def); X if (str == NULL) X str = def; X break; X case ASK_ERR: X str = tty_str("Please type a new %s: ", expl, md, def); X break; X } X X return str; X} X Xint Xenq_int(expl, md, def, max) X char *expl; X{ X int res; X char deftxt[MAXSTR]; X X VOID(sprintf(deftxt, "%d", def)); X inmood (md) { X char *str = enq_str(expl, mood, deftxt); X char *ptr = str; X char ch; X X res = 0; X while ((ch = *ptr++) != EOS) { X int dig = char2int(ch) -'0'; X X if (dig < 0 || dig > 9) { X res = -1; X break; X } X if (res > max/10 || res*10 > max - dig) { X /* airtight, waterproof and overflow-resistant */ X res = -2; X break; X } X res = res*10 + dig; X } X iferr (res == -1) { X printf("The %s `%s' is not numeric\n", X expl2str(expl), str); X enderr; X } X iferr (res == -2) { X printf("The %s `%s' is too large\n", X expl2str(expl), str); X printf("The maximum value is %d\n", max); X enderr; X } X endmood; X } X return res; X} X Xint Xisascstr(str) X char *str; X{ X char ch; X X while ((ch = *str++) != EOS) X if (!is_ascii95(ch)) X return FALSE; X return TRUE; X} X Xint Xfld2int(addr, size) X char *addr; X{ X int res = 0, i; X X for (i = 0; i < size; i++) { X char ch = addr[i]; X int dig = char2int(ch) - '0'; X X if (ch == SP) X continue; X if (dig < 0 || dig > 9) X return -1; X res = res * 10 + dig; X } X return res; X} X Xchar * /* transient */ Xfld2str(addr, size) X char *addr; X{ X static char str[MAXSTR]; X int i; X X for (i = 0; i < size; i++) X if (i < MAXSTR-1) X str[i] = addr[i]; X while (i > 0 && str[i-1] == SP) X i--; X str[i] = EOS; X return str; X} X Xfld2fld(str, s1, addr, s2) X char *str, *addr; X{ X if (s1 != s2) X abort(); X while (s1-- > 0) X *addr++ = *str++; X} X Xstr2fld(str, addr, size) X char *str, *addr; X{ X while (size-- > 0) X *addr++ = *str != EOS ? *str++ : SP; X} X Xchar * /* transient */ Xchar2str(ch) { X static char buff[7]; X X if (is_ascii95(ch)) X VOID(sprintf(buff, "%c", ch)); X else X VOID(sprintf(buff, "\\[%03o]", char2int(ch))); X return buff; X} X X/* X * `prf_s' prints a possibly ugly string `s' under a format `f' that may X * be so long that it normally blows up the `printf' routine. X */ Xprf_s(f, s) X char *f, *s; X{ X char fch; X X while ((fch = *f++) != EOS) { X if (fch != '%') X putchar(fch); X else { X int sch; X X f++; X while ((sch = *s++) != EOS) X printf("%s", char2str(sch)); X } X } X} X Xerrors(str) X char *str; X{ X printf("%s\n", str); X if (tf != NULL) X tpclose(tf); X exit(1); X} X Xstruct format * Xformat_of_type(ch) X char ch; X{ X struct format *fm; X X for (fm = &formats[0]; fm->type != EOS; fm++) X if (fm->type == ch) X return fm; X return NULL; X} + END-OF-FILE ansi.c chmod 'u=rw,g=r,o=r' \a\n\s\i\.\c set `sum \a\n\s\i\.\c` sum=$1 case $sum in 48369) :;; *) echo 'Bad sum in '\a\n\s\i\.\c >&2 esac echo Extracting \e\t\o\a\.\c sed 's/^X//' > \e\t\o\a\.\c << '+ END-OF-FILE '\e\t\o\a\.\c X/* This file is part of the magtape handling package MAG. X Written by Dick Grune, Vrije Universiteit, Amsterdam. X*/ X X/* To convert from EBCDIC to Ascii you need the table X USASCII-8 TO EBCDIC-8 CORRESPONDENCE rather than the reverse, X which strikes me as kind of counterintuitive. X X This table is Table 4 from X Communications of the ACM, Vol 11, #11, Nov 1968, p 787. X*/ X X#define S(c,r) (c<<4) + r /* implements the C/R convention */ X Xchar _etoa[] = { /* to be used in ebc2asc() */ X /* col 0 */ X S( 0, 0), S( 0, 1), S( 0, 2), S( 0, 3), X S( 9,12), S( 0, 9), S( 8, 6), S( 7,15), X S( 9, 7), S( 8,13), S( 8,14), S( 0,11), X S( 0,12), S( 0,13), S( 0,14), S( 0,15), X /* col 1 */ X S( 1, 0), S( 1, 1), S( 1, 2), S( 1, 3), X S( 9,13), S( 8, 5), S( 0, 8), S( 8, 7), X S( 1, 8), S( 1, 9), S( 9, 2), S( 8,15), X S( 1,12), S( 1,13), S( 1,14), S( 1,15), X /* col 2 */ X S( 8, 0), S( 8, 1), S( 8, 2), S( 8, 3), X S( 8, 4), S( 0,10), S( 1, 7), S( 1,11), X S( 8, 8), S( 8, 9), S( 8,10), S( 8,11), X S( 8,12), S( 0, 5), S( 0, 6), S( 0, 7), X /* col 3 */ X S( 9, 0), S( 9, 1), S( 1, 6), S( 9, 3), X S( 9, 4), S( 9, 5), S( 9, 6), S( 0, 4), X S( 9, 8), S( 9, 9), S( 9,10), S( 9,11), X S( 1, 4), S( 1, 5), S( 9,14), S( 1,10), X /* col 4 */ X S( 2, 0), S(10, 0), S(10, 1), S(10, 2), X S(10, 3), S(10, 4), S(10, 5), S(10, 6), X S(10, 7), S(10, 8), S( 5,11), S( 2,14), X S( 3,12), S( 2, 8), S( 2,11), S( 2, 1), X /* col 5 */ X S( 2, 6), S(10, 9), S(10,10), S(10,11), X S(10,12), S(10,13), S(10,14), S(10,15), X S(11, 0), S(11, 1), S( 5,13), S( 2, 4), X S( 2,10), S( 2, 9), S( 3,11), S( 5,14), X /* col 6 */ X S( 2,13), S( 2,15), S(11, 2), S(11, 3), X S(11, 4), S(11, 5), S(11, 6), S(11, 7), X S(11, 8), S(11, 9), S( 7,12), S( 2,12), X S( 2, 5), S( 5,15), S( 3,14), S( 3,15), X /* col 7 */ X S(11,10), S(11,11), S(11,12), S(11,13), X S(11,14), S(11,15), S(12, 0), S(12, 1), X S(12, 2), S( 6, 0), S( 3,10), S( 2, 3), X S( 4, 0), S( 2, 7), S( 3,13), S( 2, 2), X X /* col 8 */ X S(12, 3), S( 6, 1), S( 6, 2), S( 6, 3), X S( 6, 4), S( 6, 5), S( 6, 6), S( 6, 7), X S( 6, 8), S( 6, 9), S(12, 4), S(12, 5), X S(12, 6), S(12, 7), S(12, 8), S(12, 9), X /* col 9 */ X S(12,10), S( 6,10), S( 6,11), S( 6,12), X S( 6,13), S( 6,14), S( 6,15), S( 7, 0), X S( 7, 1), S( 7, 2), S(12,11), S(12,12), X S(12,13), S(12,14), S(12,15), S(13, 0), X /* col A */ X S(13, 1), S( 7,14), S( 7, 3), S( 7, 4), X S( 7, 5), S( 7, 6), S( 7, 7), S( 7, 8), X S( 7, 9), S( 7,10), S(13, 2), S(13, 3), X S(13, 4), S(13, 5), S(13, 6), S(13, 7), X /* col B */ X S(13, 8), S(13, 9), S(13,10), S(13,11), X S(13,12), S(13,13), S(13,14), S(13,15), X S(14, 0), S(14, 1), S(14, 2), S(14, 3), X S(14, 4), S(14, 5), S(14, 6), S(14, 7), X /* col C */ X S( 7,11), S( 4, 1), S( 4, 2), S( 4, 3), X S( 4, 4), S( 4, 5), S( 4, 6), S( 4, 7), X S( 4, 8), S( 4, 9), S(14, 8), S(14, 9), X S(14,10), S(14,11), S(14,12), S(14,13), X /* col D */ X S( 7,13), S( 4,10), S( 4,11), S( 4,12), X S( 4,13), S( 4,14), S( 4,15), S( 5, 0), X S( 5, 1), S( 5, 2), S(14,14), S(14,15), X S(15, 0), S(15, 1), S(15, 2), S(15, 3), X /* col E */ X S( 5,12), S( 9,15), S( 5, 3), S( 5, 4), X S( 5, 5), S( 5, 6), S( 5, 7), S( 5, 8), X S( 5, 9), S( 5,10), S(15, 4), S(15, 5), X S(15, 6), S(15, 7), S(15, 8), S(15, 9), X /* col F */ X S( 3, 0), S( 3, 1), S( 3, 2), S( 3, 3), X S( 3, 4), S( 3, 5), S( 3, 6), S( 3, 7), X S( 3, 8), S( 3, 9), S(15,10), S(15,11), X S(15,12), S(15,13), S(15,14), S(15,15) X}; X + END-OF-FILE etoa.c chmod 'u=rw,g=r,o=r' \e\t\o\a\.\c set `sum \e\t\o\a\.\c` sum=$1 case $sum in 05699) :;; *) echo 'Bad sum in '\e\t\o\a\.\c >&2 esac echo Extracting \a\n\s\i\r\.\c sed 's/^X//' > \a\n\s\i\r\.\c << '+ END-OF-FILE '\a\n\s\i\r\.\c X/* This file is part of the magtape handling package MAG. X Written by Dick Grune, Vrije Universiteit, Amsterdam. X*/ X X/* X * Name: ansir, read ANSI standard labelled tape X * Version: 820314 X */ X X#define MSGUSE "Usage: ansir [-cfhlmijnpg] [ name ... ]" X Xextern char *strncpy(); X X#include "aux.h" X#include "tp.h" X#include "ansi.h" X#include "etoa.h" X X#define MAXBLK TP_MAXB X#define MINSIZE 6 /* smaller is a noise block */ X#define CRECSEP "\n" /* record separator for coded files */ X Xchar iflag = FALSE, jflag = FALSE, nflag = FALSE, pflag = FALSE, gflag = FALSE; Xchar ok_fln, ok_rct, ok_blk, ok_rec, ok_bfo, ok_loc, skip_it; Xchar **filelist = NULL; X Xchar *labcode = NULL; Xchar *filecode = NULL; /* may be `ascii', `ebcdic' or `binary' */ Xchar *ascii = "ASCII"; Xchar *ebcdic = "EBCDIC"; Xchar *binary = "BINARY"; Xchar binrecsep[MAXSTR]; X Xint bsize = 0; Xchar block[MAXBLK]; X X#define MAXUGLY 99 /* upper limit for tallying */ Xchar uglies[256]; /* for tallying non-UNIX-ASCII chars */ Xlong tot_uglies; X Xint HDR1blc; /* block count as found in HDR1-label */ X Xmain(argc, argv) X int argc; X char *argv[]; X{ X argc--, argv++; X while (argc > 0 && argv[0][0] == '-') { X char *pp = argv[0]; X X while (*++pp) { X switch (*pp) { X /* insert cases to handle the standard options */ X#include "options.h" X /* special options */ X case 'g': X gflag = TRUE; X break; X case 'i': X iflag = TRUE; X break; X case 'j': X iflag = jflag = TRUE; X break; X case 'n': X nflag = TRUE; X break; X case 'p': X pflag = TRUE; X break; X } X } X argc--, argv++; X } X X if (argc > 0) X filelist = argv; X X tf = tpopen(unit, nmdns, "rx"); X nextblk(); X X lblVOL1(); X lblUSR("UVL"); X while (bsize > 0) { X clearflags(); X lblHDR1(); X lblHDR2(); X lblUSR("HDR"); X lblUSR("UHL"); X read_tm(); X copy(); X lblEOF1(); X lblEOF2(); X lblUSR("EOF"); X lblUSR("UTL"); X read_tm(); X } X if (pflag) X printf("\nEnd of tape\n"); X tpclose(tf); X exit(0); X XLbad: X errors(MSGUSE); X exit(1); X} X Xclearflags() { X ok_fln = ok_rct = ok_blk = ok_rec = ok_bfo = ok_loc = skip_it = FALSE; X} X X/* X * Reads the VOL1-label and prints its contents X */ X XlblVOL1() { X X if (!label("VOL1", Whole(VOL1buf))) { X missing("VOL1"); X return; X } X X if (pflag) X prVOL1(); X} X XlblUSR(idf) X char *idf; X{ X char USRnbuf[80]; X X while (label(idf, Whole(USRnbuf))) X if (pflag && !skip_it) { X prhead(Labidf(USRnbuf)); X prfield("Contents", Contents(USRnbuf)); X } X} X X/* X * Reads the HDR1-label, prints its contents, and sets `filename' X */ X XlblHDR1() { X X filseqnum++; X if (!label("HDR1", Whole(HDR1buf))) { X missing("HDR1"); X ok_fln = FALSE; X return; X } X X strcpy(filename, fld2str(Fileidf(HDR1buf))); X ok_fln = TRUE; X X if (!interesting(filename)) { X skip_it = TRUE; X return; X } X X if (pflag) X prHDR1(); X X if (fld2int(Filsecnum(HDR1buf)) != filsecnum) { X print_loc(); X printf("File section number not %d\n", filsecnum); X } X if (fld2int(Filseqnum(HDR1buf)) != filseqnum) { X print_loc(); X printf("File sequence number not in order\n"); X } X X HDR1blc = fld2int(Blkcount(HDR1buf)); X if (chk_int("block count", HDR1blc) && HDR1blc != 0) { X print_loc(); X printf("Block count starts from %d\n", HDR1blc); X } X} X X/* X * Reads the HDR2-label, prints its contents and sets X * `recformat', `blklength', `reclength' and `bufoffset'. X */ X XlblHDR2() { X int found = label("HDR2", Whole(HDR2buf)); X X if (skip_it) X return; X X if (!found) { X missing("HDR2"); X ok_rct = ok_blk = ok_rec = ok_bfo = FALSE; X return; X } X X if (pflag) X prHDR2(); X X fld2fld(Recformat(HDR2buf), Whole(rectype)); X ok_rct = TRUE; X blklength = fld2int(Blklength(HDR2buf)); X ok_blk = chk_int("block length", blklength); X reclength = fld2int(Reclength(HDR2buf)); X ok_rec = chk_int("record length", reclength); X bufoffset = fld2int(Bufoffset(HDR2buf)); X ok_bfo = chk_int("buffer offset", bufoffset); X} X Xint Xlabel(idf, addr, size) X char *idf, *addr; X{ X if (bsize <= 0) X return FALSE; X if (labcode != NULL) X return is_lab(idf, addr, size); X labcode = ascii; X if (is_lab(idf, addr, size)) X return TRUE; X labcode = ebcdic; X if (is_lab(idf, addr, size)) X return TRUE; X labcode = NULL; X return FALSE; X} X Xint Xis_lab(idf, addr, size) X char *idf, *addr; X{ X int sz = bsize < size ? bsize : size; X X VOID(strncpy(addr, block, sz)); X if (labcode == ebcdic) X conv(addr, sz); X str2fld("", addr+sz, size-sz); X if (strhead(idf, addr)) { X nextblk(); X return TRUE; X } X return FALSE; X} X Xint Xstrhead(s1, s2) X char *s1, *s2; X{ X while (*s1) X if (*s1++ != *s2++) X return FALSE; X return TRUE; X} X Xread_tm() { X if (bsize == 0) X nextblk(); X else { X print_loc(); X printf("Tape mark missing\n"); X } X} X Xnextblk() { X X do bsize = tpread(tf, block, MAXBLK); X while (bsize > 0 && bsize < MINSIZE); X} X Xint Xinteresting(fn) X char *fn; X{ X char **lst = filelist, *nm; X X if (lst == NULL) X return TRUE; X while ((nm = *lst++) != NULL) X if (strcmp(nm, fn) == 0) X return TRUE; X return FALSE; X} X Xconv(addr, size) X char *addr; X{ X while (size-- > 0) { X *addr = ebc2asc(*addr); X addr++; X } X} X Xchar Xasc2ebc(ch) X char ch; X{ X char ch1 = 0; X X while (ch != ebc2asc(ch1)) X ch1++; X return ch1; X} X X/* X * copy one file X */ X Xcopy() { X X init_copy(); X X do copypart(); X while (change_tape()); X X end_copy(); X} X Xinit_copy() { X int i; X X blkcount = reccount = 0; X tot_uglies = 0L; X for (i = 0; i < n_items(uglies); i++) X uglies[i] = 0; X X getpars(); X} X Xend_copy() { X X if (pflag && !skip_it) { X printf("\n"); X if (file != NULL) X printf("Record count: %d\n", reccount); X printf("Block count: %d\n", blkcount); X if (file != NULL) X prf_s("File copied: %s\n", filename); X else X printf("File skipped\n"); X } X X if (file != NULL) { X X VOID(fclose(file)); X file = NULL; X if (tot_uglies != 0L) { X int i; X X print_loc(); X printf("File contained %ld non-printing character%s:\n", X english(tot_uglies)); X for (i = 0; i < n_items(uglies); i++) { X int n = char2int(uglies[i]); X X if (n != 0) { X if (n <= MAXUGLY) X printf("%s: %d\n", X char2str(i), n); X else printf("%s: >%d\n", X char2str(i), MAXUGLY); X } X } X } X } X} X X/* X * getpars sets `filename', `filecode', `recformat' X * and as many further parameters as is necessary X */ X Xextern struct format fdummy; X Xgetpars() { X X if (nflag || skip_it) { X recformat = &fdummy; X return; X } X X inmood (!ok_fln ? ASK_YES : iflag ? ASK_SUG : ASK_NO) { X strcpy(filename, enq_str("\ X The `file name' is the name under which the tape file will be\n\ X stored on disk. The named file must not already exist.\n\ X Use a minus - to skip the file.\n", X mood, filename)); X X if (strcmp(filename, "-") == 0) { X recformat = &fdummy; X return; X } X iferr (!isascstr(filename)) { X prf_s("Filename %s contains non-printing chars\n", X filename); X enderr; X } X iferr ((file = fopen(filename, "r")) != NULL) { X prf_s("File %s already exists\n", filename); X VOID(fclose(file)); X file = NULL; X enderr; X } X iferr ((file = fopen(filename, "w")) == NULL) { X prf_s("Cannot create %s\n", filename); X enderr; X } X endmood; X } X X inmood ( labcode == NULL && filecode == NULL ? ASK_YES : X labcode == NULL || iflag ? ASK_SUG : ASK_NO X ) { X filecode = enq_str("\ X The `character code' is the code of the file on tape; it may be\n\ X ASCII, EBCDIC (usual for IBM-tapes) or BINARY (no conversion).\n\ X When in doubt, use %s.\n", X mood, X filecode != NULL ? filecode : X labcode != NULL ? labcode : X ascii); X switch (filecode[0]) { X case 'A': X filecode = ascii; X break; X case 'B': X filecode = binary; X break; X case 'E': X filecode = ebcdic; X break; X default: X printf("`%s' is not a character code\n", filecode); X filecode = NULL; X } X iferr (filecode == NULL) { X printf("Specify %s, %s or %s\n", X ascii, ebcdic, binary); X enderr; X } X endmood; X } X X if (filecode == binary) X strcpy(binrecsep, X enq_str("\ X The `record separator' only applies to the character code\n\ X BINARY, where it specifies what character(s) should be written\n\ X to disk for each end-of-record on the tape. You will probably\n\ X want it to be empty, but, when in doubt, try a recognizable\n\ X string like }}}} and examine the results.\n", X ASK_SUG, binrecsep)); X X inmood (!ok_rct || jflag ? ASK_SUG : ASK_NO) { X char *rct = enq_str("\ X The `record format' tells how the block on tape must be cut into\n\ X text records (lines). There are five standard ways to do so:\n\ X F: each N consecutive characters form a record, where N is the\n\ X `record length',\n\ X D: a header in each record tells its length,\n\ X U: each block is one record,\n\ X S: a special format in which records may be longer than blocks,\n\ X V: IBM Variable format.\n\ X When in doubt, use %s and examine the results, or try them all.\n", X mood, !ok_rct ? "U" : fld2str(Whole(rectype))); X X iferr ( strlen(rct) != 1 X || (recformat = format_of_type(rct[0])) == NULL X ) { X printf("`%s' is not an ANSI format\n", rct); X printf("Please specify F, D, U, S or V\n"); X enderr; X } X iferr (recformat->cpblk == NULL) { X printf("%s-format not implemented\n", rct); X enderr; X } X str2fld(rct, Whole(rectype)); X endmood; X } X X inmood (!ok_blk || jflag ? ASK_SUG : ASK_NO) { X blklength = enq_int("\ X The `block length' is the maximum number of significant\n\ X characters in any physical block (as demarcated by two\n\ X interrecord gaps) on the tape. Unless you know the exact value,\n\ X use a large number like %s.\n", X mood, !ok_blk ? MAXBLK : blklength, MAXBLK); X X iferr (blklength < MINSIZE) { X printf("Block length cannot be smaller than %d\n", X MINSIZE); X enderr; X } X endmood; X } X X (*recformat->checkpar)(); X X bufoffset = enq_int("\ X The `buffer offset' is the position in each block on the tape at\n\ X which the real information starts. Unless you know the exact\n\ X value, use 0.\n", X !ok_bfo || jflag ? ASK_SUG : ASK_NO, X !ok_bfo ? 0 : bufoffset, X blklength - 1); X} X Xcopypart() { X while (bsize > 0) { X int used; X X ++blkcount; X if (bsize > blklength) { X print_loc(); X printf("Actual block size = %d, not %d as in label\n", X bsize, blklength); X } X if (filecode == ebcdic) X conv(block, bsize); X used = bufoffset; X used += (*recformat->cpblk) (&block[used], bsize-used); X if (!filler(&block[used], bsize-used)) { X print_loc(); X printf("At block %d, after record %d:", X blkcount, reccount); X printf(" %d char%s garbage ignored\n", X english(bsize-used)); X } X nextblk(); X } X read_tm(); X} X Xint Xchange_tape() { X return FALSE; /* not yet implemented */ X} X XcheckF() { X X inmood (!ok_rec || jflag ? ASK_SUG : ASK_NO) { X reclength = enq_int("\ X The `record length' is a number N such that a <newline> is\n\ X assumed after each N characters read from tape. When in doubt,\n\ X use %s and examine the results for a better value.\n", X mood, X !ok_rec || blklength < reclength ? X blklength : reclength, X blklength); X X iferr (reclength == 0) { X printf("Record length cannot be zero\n"); X enderr; X } X endmood; X } X} X X Xint XcpFblk(buf, size) X char *buf; X{ X int i = 0; X X while (i <= size - reclength) { X char *rec = &buf[i]; X int sz = reclength; X X reccount++; X if (filecode != binary) { X char pad = rec[sz-1]; X X if (!is_ascii95(pad) || pad == SP) /* liberal */ X while (sz > 0 && rec[sz-1] == pad) X sz--; X } X put_rec(rec, sz); X put_eor(); X i += reclength; X } X return i; X} X Xint XcpUblk(buf, size) X char *buf; X{ X reccount++; X put_rec(buf, size); X put_eor(); X return size; X} X X#define DVPREF 4 /* size of D or V length prefix */ X Xint XcpDVblk(buf, size) X char *buf; X{ X int i = rectype[0] == 'V' ? DVPREF : 0; X X while (size - i >= DVPREF) { X char *rec = &buf[i]; X int sz = DVlength(rec); X X if (sz < DVPREF || size - i - sz < 0) X break; X X reccount++; X put_rec(rec + DVPREF, sz - DVPREF); X put_eor(); X i += sz; X } X return i; X} X Xint XDVlength(buf) X char *buf; X{ X int res = 0; X X if (rectype[0] == 'V') { X int i; X for (i = 0; i <= 1; i++) { X char ch = buf[i]; X res = res*256 + X char2int(filecode == ebcdic ? X asc2ebc(ch) : ch); X } X } X else X res = fld2int(buf, DVPREF); X return res; X} X X#define SPREF 5 /* size of S length prefix */ X Xint XcpSblk(buf, size) X char *buf; X{ X int i = 0; X X while (size - i >= SPREF) { X char *rec = &buf[i]; X char ind = rec[0]; X int sz = fld2int(rec+1, SPREF-1); X X if (sz < SPREF || size - i - sz < 0) X break; X X if (ind == '0' || ind == '1') X reccount++; X put_rec(rec + SPREF, sz - SPREF); X if (ind == '0' || ind == '3') X put_eor(); X i += sz; X } X return i; X} X Xskip() { X return; X} X Xint Xskpblk(buf, size) X char *buf; X{ X VOID(buf); X return size; X} X Xint Xfiller(addr, size) X char *addr; X{ X char ch = *addr; X X while (size--) X if (ch != *addr++) X return FALSE; X return TRUE; X} X Xstruct format formats[] = { X {'F', checkF, cpFblk}, X {'U', skip, cpUblk}, X {'D', skip, cpDVblk}, X {'V', skip, cpDVblk}, /* to cater for you know whom */ X {'S', skip, cpSblk}, X {EOS, NULL, NULL} X}; X Xstruct format fdummy = {EOS, skip, skpblk}; X Xput_rec(rec, size) X char *rec; X{ X int i; X X for (i = 0; i < size; i++) { X int ch = char2int(rec[i]); X X if (filecode == binary || is_ascii95(ch)) X putc(ch, file); X else { X fprintf(file, "%s", char2str(ch)); X if (uglies[ch] <= MAXUGLY) X uglies[ch]++; X tot_uglies++; X } X } X} X Xput_eor() { X char *sep = filecode == binary ? binrecsep : CRECSEP; X char ch; X X while ((ch = *sep++) != EOS) X putc(ch, file); X} X X/* X * Reads the EOF1-label and checks block count X */ X XlblEOF1() { X int bcount; X int found = label("EOF1", Whole(HDR1buf)); X X if (skip_it) X return; X X if (!found) { X missing("EOF1"); X return; X } X X bcount = fld2int(Blkcount(HDR1buf)); X X if (pflag) X prHDR1(); X X if (HDR1blc >= 0 && bcount != blkcount + HDR1blc) { X print_loc(); X printf( X "File holds %d block%s whereas labels report %d block%s\n", X english(blkcount), english(bcount - HDR1blc)); X } X} X X/* X * Read EOF2-label X */ X XlblEOF2() { X int found = label("EOF2", Whole(HDR2buf)); X X if (skip_it) X return; X X if (!found) { X missing("EOF2"); X return; X } X X if (pflag) X prHDR2(); X} X X/* X * Print routines X */ X XprVOL1() { X prhead(Labidf(VOL1buf)); X printf("The labels are in %s\n", labcode); X prfield("Volume serial number", Volidf(VOL1buf)); X prfield("Volume accessibility", Volacc(VOL1buf)); X prunused(Sp1(VOL1buf)); X prfield("Owner identification", Ownidf(VOL1buf)); X prunused(Sp2(VOL1buf)); X prfield("Label version", Labvers(VOL1buf)); X} X XprHDR1() { X prhead(Labidf(HDR1buf)); X prfield("File identifier", Fileidf(HDR1buf)); X prfield("Set identifier", Filesetidf(HDR1buf)); X prfield("File section number", Filsecnum(HDR1buf)); X prfield("File sequence number", Filseqnum(HDR1buf)); X if (gflag) { X prfield("Generation number", Gennum(HDR1buf)); X prfield("Generation version number", Genversnum(HDR1buf)); X } X prfield("Creation date", Creatdate(HDR1buf)); X prfield("Expiration date", Expirdate(HDR1buf)); X prfield("File accessibility", Fileacc(HDR1buf)); X prfield("Block count", Blkcount(HDR1buf)); X prfield("System code", Syscode(HDR1buf)); X prunused(Sp3(HDR1buf)); X} X XprHDR2() { X prhead(Labidf(HDR2buf)); X prfield("Record format", Recformat(HDR2buf)); X prfield("Block length", Blklength(HDR2buf)); X prfield("Record length", Reclength(HDR2buf)); X prfield("System software", Syssoftw(HDR2buf)); X prfield("Buffer offset", Bufoffset(HDR2buf)); X prunused(Sp4(HDR2buf)); X} X Xprhead(addr, size) X char *addr; X{ X printf("\nInformation from the %s-label\n", fld2str(addr, size)); X} X Xprfield(nm, addr, size) X char *nm, *addr; X{ X char *str = fld2str(addr, size); X X printf("%s: ", nm); X prf_s("%s\n", *str == EOS ? sps2txt(size) : str); X} X Xprunused(addr, size) X char *addr; X{ X char *str = fld2str(addr, size); X X if (strlen(str) > 0) X prf_s("Unused field: %s\n", str); X} X Xmissing(idf) X char *idf; X{ X print_loc(); X printf("%s-label missing\n", idf); X} X Xint Xchk_int(nm, val) X char *nm; X{ X if (val < 0) { X print_loc(); X printf("Garbage in %s field\n", nm); X return FALSE; X } X else X return TRUE; X} X Xprint_loc() { X X if (ok_loc || pflag) X return; X if (ok_fln) X prf_s("\n*** At file `%s':\n", filename); X else X printf("\n*** At file number %d:\n", filseqnum); X ok_loc = TRUE; X} + END-OF-FILE ansir.c chmod 'u=rw,g=r,o=r' \a\n\s\i\r\.\c set `sum \a\n\s\i\r\.\c` sum=$1 case $sum in 51802) :;; *) echo 'Bad sum in '\a\n\s\i\r\.\c >&2 esac echo Extracting \a\n\s\i\w\.\c sed 's/^X//' > \a\n\s\i\w\.\c << '+ END-OF-FILE '\a\n\s\i\w\.\c X/* This file is part of the magtape handling package MAG. X Written by Dick Grune, Vrije Universiteit, Amsterdam. X*/ X X/* X * Name: ansiw, write ANSI standard labelled tape X * Version: 820314 X */ X X#define MSGUSE "Usage: ansiw [-cfhlmignpv] [ file ... ]" X X#include "aux.h" X#include "sys.h" X#include "tp.h" X#include "tploc.h" /* to get SYSCODE */ X#include "ansi.h" X X#define MAXBLK 2048 X#define MINBLK 18 X#define FILLER '^' X Xchar iflag = FALSE, gflag = FALSE, pflag = FALSE, vflag = FALSE; Xchar block[MAXBLK]; X Xstruct DD { X long size; X long lrecl; X char ascii95; X char example; X} dd; Xstruct DD empty_dd = {0L, 0L, TRUE, EOS}; X X#define divis(m, n) ((n)!=0&&(m)%(n)==0) X Xmain(argc, argv) X int argc; X char *argv[]; X{ X argc--, argv++; X while (argc > 0 && argv[0][0] == '-') { X char *pp = argv[0]; X X while (*++pp) { X switch (*pp) { X /* insert cases to handle the standard options */ X#include "options.h" X /* special options */ X case 'g': X gflag = TRUE; X break; X case 'i': X iflag = TRUE; X break; X case 'n': X unit = TP_IMAG; X nmdns = "/dev/null"; X break; X case 'p': X pflag = TRUE; X break; X case 'v': X vflag = TRUE; X break; X } X } X argc--, argv++; X } X tf = tpopen(unit, nmdns, "w"); X X check_args(argc, argv); X X lblVOL1(iflag || vflag ? ASK_SUG : ASK_NO); X X while (argc-- != 0) { X strcpy(filename, argv[filseqnum]); X filseqnum++; X blkcount = 0; X X opendd(filename); X if (file == NULL) { X printf(">>> File %s ", filename); X errors("has suddenly disappeared!!!"); X } X lblHDR1(iflag ? ASK_SUG : ASK_NO); X lblHDR2(iflag ? ASK_SUG : ASK_NO); X wrt_tm(); X copy(); X wrt_tm(); X lblEOF1(); X lblEOF2(); X wrt_tm(); X } X X wrt_tm(); X tpclose(tf); X exit(0); X XLbad: X errors(MSGUSE); X exit(1); X} X Xcheck_args(c, v) X char *v[]; X{ X char ok = TRUE; X X while (c-- > 0) { X int f = open(*v, 0); X X if (f < 0) { X printf("Cannot open %s\n", *v); X ok = FALSE; X } X else VOID(close(f)); X v++; X } X if (!ok) X errors("Stop"); X} X Xwrt_tm() X{ /* writes a tapemark */ X tpwrite(tf, "", 0); X} X Xlong Xtab(p) X long p; /* the position in which a tab from p would land */ X{ X return (p/8+1)*8; X} X X/* X * `opendd' opens the file `fn' and determines its `dd' parameters X */ X Xopendd(fn) X char *fn; X{ X int ch; X long lr; X X dd = empty_dd; X if ((file = fopen(fn, "r")) == NULL) X return; X X lr = 0L; X while ((ch = getc(file)) != EOF) { X dd.size++; X if (ch == NL) { X if (lr > dd.lrecl) X dd.lrecl = lr; X lr = 0L; X } X else X if (ch == TAB) { X lr = tab(lr); X } X else { X lr++; X if (!is_ascii95(ch)) { X dd.ascii95 = FALSE; X dd.example = ch; X } X } X } X if (lr > dd.lrecl) X dd.lrecl = lr; X X VOID(fclose(file)); X file = fopen(fn, "r"); X} X X/* X * the writing of labels X */ X XlblVOL1(md) { X char *owner = username(); X X str2fld("", Whole(VOL1buf)); X str2fld("VOL1", Labidf(VOL1buf)); X X enq_fld("\ X The `volume serial number' is the six-character identification\n\ X number of the tape itself, as it should appear on the sticker on\n\ X the reel. When in doubt, use the default %s.\n", X md, "222222", Volidf(VOL1buf)); X enq_fld("\ X The `volume accessibility symbol' is a single character,\n\ X recorded on the tape, which indicates how publicly accessible the\n\ X whole tape is. It is not well defined, but a single space is\n\ X generally taken to mean: accessible by anybody.\n", X md, " ", Volacc(VOL1buf)); X enq_fld("\ X The `owner identification' is the name of the owner, as recorded\n\ X on the tape. On some systems it interacts with the file\n\ X accessibility symbol. When in doubt, specify a short string of\n\ X letters.\n", X owner == NULL ? ASK_YES : md, owner, Ownidf(VOL1buf)); X str2fld("1", Labvers(VOL1buf)); X X tpwrite(tf, Whole(VOL1buf)); X} X XlblHDR1(md) { X char *today = sysdate(); X X str2fld("", Whole(HDR1buf)); X str2fld("HDR1", Labidf(HDR1buf)); X enq_fld("\ X The `file identifier' is the name of the file, as recorded on\n\ X the tape. When in doubt, specify a six-letter mnemonic name.\n", X md, filename, Fileidf(HDR1buf)); X X fld2fld(Volidf(VOL1buf), Filesetidf(HDR1buf)); X int2fld(filsecnum, Filsecnum(HDR1buf)); X int2fld(filseqnum, Filseqnum(HDR1buf)); X enq_num("\ X The `generation number' is a counter that some operating systems\n\ X attach to a file and that is increased each time the file is\n\ X updated. Use 1.\n", X gflag ? md : ASK_NO, 1, Gennum(HDR1buf)); X enq_num("\ X The `generation version number' tells how often an attempt to\n\ X write the file to tape has failed. Use 0.\n", X gflag ? md : ASK_NO, 0, Genversnum(HDR1buf)); X dat2fld(today, Creatdate(HDR1buf)); X enq_dat("\ X The `expiration date' is the date, recorded on the tape, after\n\ X which the file may be overwritten. The format is 2 digits for\n\ X the year, followed by 3 digits for the day in the year, e.g.,\n\ X 86365 for the last day of 1986. When in doubt, use today's date,\n\ X %s, to make the receiver's life easier.\n", X md, today, Expirdate(HDR1buf)); X enq_fld("\ X The `file accessibility symbol' is a single character, recorded\n\ X on the tape, which indicates how publicly accessible the file is.\n\ X It is not well defined, but a single space is generally taken to\n\ X mean: accessible by anybody.\n", X md, " ", Fileacc(HDR1buf)); X int2fld(blkcount, Blkcount(HDR1buf)); X X str2fld(SYSCODE /* from tploc.h */, Syscode(HDR1buf)); X X tpwrite(tf, Whole(HDR1buf)); X} X XlblHDR2(md) { X X str2fld("", Whole(HDR2buf)); X str2fld("HDR2", Labidf(HDR2buf)); X X if (!iflag) { X str2fld("F", Whole(rectype)); X blklength = 1920; X reclength = 80; X } X X if (!dd.ascii95) { X printf("`%s' contains non-ASCII95 characters, e.g., %s\n", X filename, char2str(dd.example)); X printf("Perhaps the file code should have been BINARY"); X str2fld("U", Whole(rectype)); X } X X if (dd.lrecl > MAXBLK) { X printf("`%s' has a record length > %d\n", filename, MAXBLK); X printf("Only U-format is possible\n"); X str2fld("U", Whole(rectype)); X recformat = format_of_type('U'); X } X else X inmood (!dd.ascii95 ? ASK_SUG : md) { X char *rct = enq_str("\ X The `record format' tells how lines from the disk file should be\n\ X converted to records to be packed into blocks to be recorded on\n\ X tape. Although many formats exist, only two are any good in\n\ X Information Interchange:\n\ X F (Fixed): spaces are added at the end of the line until its\n\ X length is `record length', and `block length'/`record length'\n\ X of these records form a block;\n\ X U (Undefined): `block length' characters are stored in a block.\n\ X Unless the disk file contains non-ASCII characters, use F.\n", X mood, fld2str(Whole(rectype))); X X iferr ( strlen(rct) != 1 X || (recformat = format_of_type(rct[0])) == NULL X || recformat->cpblk == NULL X ) { X printf( X "Only F- and U-formats are allowed for portability\n" X ); X enderr; X } X X str2fld(rct, Whole(rectype)); X endmood; X } X X (*recformat->checkpar)(md); X X fld2fld(Whole(rectype), Recformat(HDR2buf)); X int2fld(blklength, Blklength(HDR2buf)); X int2fld(reclength, Reclength(HDR2buf)); X int2fld(bufoffset, Bufoffset(HDR2buf)); X X tpwrite(tf, Whole(HDR2buf)); X} X XcheckF(md) { X int lr; X X inmood (md) { X getBlklength(mood); X iferr (blklength < reclength) { X printf("Block length < phys. record length (=%ld)\n", X dd.lrecl); X enderr; X } X endmood; X } X X lr = dd.lrecl; X while (!divis(blklength, lr)) X lr++; X if (lr < 80 && divis(blklength, 80)) X lr = 80; X reclength = lr; X X inmood (md) { X reclength = enq_int("\ X The `record length' is the number of characters into which each\n\ X line (record) is stretched before it is written to tape. It must\n\ X divide the block length. Unless the receiver has been very\n\ X specific, use %s.\n", X mood, reclength, blklength); X iferr (reclength == 0 || !divis(blklength, reclength)) { X printf( X "The block length is not a multiple of the record length\n" X ); X enderr; X } X iferr (reclength < dd.lrecl) { X printf("Record length < phys. record length (=%ld)\n", X dd.lrecl); X enderr; X } X endmood; X } X} X XcheckU(md) { X getBlklength(md); X reclength = blklength; X} X XgetBlklength(md) { X inmood (md) { X blklength = X enq_int("\ X The `block length' is the number of characters in each physical\n\ X block written to tape. Unless the receiver has specified\n\ X something else, use %s.\n", X mood, X (rectype[0] == 'F' && dd.lrecl > 1920) ? X MAXBLK : !iflag ? 1920 : blklength, X MAXBLK); X iferr (blklength < MINBLK) { X printf("The minimum block length is %d\n", MINBLK); X enderr; X } X endmood; X } X} X X XlblEOF1() { X str2fld("EOF1", Labidf(HDR1buf)); X int2fld(blkcount, Blkcount(HDR1buf)); X tpwrite(tf, Whole(HDR1buf)); X} X XlblEOF2() { X str2fld("EOF2", Labidf(HDR2buf)); X tpwrite(tf, Whole(HDR2buf)); X} X X/* X * the copying of the file X */ X Xcopy() { X int size; X X blkcount = reccount = 0; X X while ((size = (*recformat->cpblk)()) > 0) { X while (size < MINBLK) X block[size++] = FILLER; X tpwrite(tf, block, size); X ++blkcount; X } X VOID(fclose(file)); X file = NULL; X if (pflag) { X printf("File name: %s\n", filename); X printf("Record format: %s\n", rectype); X printf("Block length: %d; number of blocks: %d\n", X blklength, blkcount); X printf("Record length: %d; number of records: %d\n\n", X reclength, reccount); X } X} X Xint XcpFblk() { X int ch; X int count = 0; X X while (count < blklength && (ch = getc(file)) != EOF) { X int rpos = 0; X reccount++; X while (ch != NL && ch != EOF) { X if (ch == TAB) { X int nrpos = (int)tab((long)rpos); X while (rpos < nrpos) { X block[count++] = SP, rpos++; X } X } X else { X block[count++] = ch, rpos++; X } X ch = getc(file); X } X while (rpos < reclength) { X block[count++] = SP, rpos++; X } X } X return count; X} X Xint XcpUblk() { X int ch; X int count = 0; X X while (count < blklength && (ch = getc(file)) != EOF) { X block[count++] = ch; X } X if (count > 0) X reccount++; X return count; X} X Xstruct format formats[] = { X {'F', checkF, cpFblk}, X {'U', checkU, cpUblk}, X {'D', NULL, NULL}, X {'S', NULL, NULL}, X {EOS, NULL, NULL} X}; X X/* X * the setting of fields X */ X Xint2fld(n, addr, size) X char *addr; X{ X addr += size; X while (size-- > 0) { X *--addr = n % 10 + '0'; X n = n / 10; X } X} X Xdat2fld(str, addr, size) X char *str, *addr; X{ X str2fld("", addr, size); X str2fld(str, Date(addr)); X} X Xenq_fld(expl, md, def, addr, size) X char *expl, *def, *addr; X{ X char *ans; X X inmood (md) { X ans = enq_str(expl, mood, def); X iferr (strlen(ans) == 0) { X printf("No empty answer allowed\n"); X enderr; X } X iferr (strlen(ans) > size) { X printf("The %s is too long\n", expl2str(expl)); X printf("The maximum length is %d character%s\n", X english(size)); X enderr; X } X iferr (!isascstr(ans)) { X printf("The %s `%s' contains non-printing chars\n", X expl2str(expl), ans); X enderr; X } X endmood; X } X str2fld(ans, addr, size); X} X Xenq_dat(expl, md, def, addr, size) X char *expl, *def, *addr; X{ X dat2fld(def, addr, size); X inmood (md) { X int yd; X X enq_fld(expl, mood, def, Date(addr)); X iferr (fld2int(Yr(addr)) < 0) { X printf("Year must be numeric\n"); X enderr; X } X yd = fld2int(Yd(addr)); X iferr (yd < 1 || yd > 366) { X printf("Date in year must be between 1 and 366\n"); X enderr; X } X endmood; X } X} X Xenq_num(expl, md, def, addr, size) X char *expl, *addr; X{ X int2fld(enq_int(expl, md, def, tento(size)-1), addr, size); X} X Xint Xtento(n) { X int res = 1; X X while (n--) X res *= 10; X return res; X} X Xprint_loc() { X /* dummy in ansiw.c; useful in ansir.c */ X return; X} + END-OF-FILE ansiw.c chmod 'u=rw,g=r,o=r' \a\n\s\i\w\.\c set `sum \a\n\s\i\w\.\c` sum=$1 case $sum in 35905) :;; *) echo 'Bad sum in '\a\n\s\i\w\.\c >&2 esac echo Extracting \c\p\t\p\.\c sed 's/^X//' > \c\p\t\p\.\c << '+ END-OF-FILE '\c\p\t\p\.\c X/* This file is part of the magtape handling package MAG. X Written by Dick Grune, Vrije Universiteit, Amsterdam. X*/ X X/* X * Name: cptp, copy tape X * Version: 820314 X * X * `Cptp' converts between real tapes and tape images on disk. X */ X X#define MSGUSE "Usage is: cptp [-cfhlmx] [of=file | if=file]" X X#include <stdio.h> X#include "aux.h" X#include "tp.h" X Xint unit = 0; Xchar *nmdns = TP_DENN; Xchar *rx = "r"; XTPFILE *from, *to; Xchar *filename; Xint size; Xchar buff[TP_MAXB]; X Xmain(argc, argv) X char *argv[]; X{ X char *arg; X X argc--, argv++; X while (argc > 0 && argv[0][0] == '-') { X char *pp = argv[0]; X X while (*++pp) { X switch (*pp) { X /* insert cases to handle the standard options */ X#include "options.h" X /* special options */ X case 'x': X rx = "rx"; X break; X } X } X argc--, argv++; X } X if (argc != 1) X goto Lbad; X arg = argv[0]; X if (arg[0] == '\0' || arg[1] != 'f' || arg[2] != '=') X goto Lbad; X filename = &arg[3]; X X tperrout(stdout); X switch (arg[0]) { X case 'o': X if (open(filename, 0) > 0) X error("Output file already exists"); X from = tpopen(unit, nmdns, rx); X to = tpopen(TP_IMAG, filename, "w"); X break; X case 'i': X from = tpopen(TP_IMAG, filename, "r"); X to = tpopen(unit, nmdns, "w"); X break; X default: X goto Lbad; X } X X while ((size = tpread(from, buff, TP_MAXB)) >= 0) { X if (size == TP_MAXB) X printf("Block too long; information may be lost\n"); X tpwrite(to, buff, size); X } X tpclose(from); X tpclose(to); X exit(0); X XLbad: X error(MSGUSE); X exit(1); X} X Xerror(str) X char *str; X{ X fprintf(stderr, "%s\n", str); X exit(1); X} + END-OF-FILE cptp.c chmod 'u=rw,g=r,o=r' \c\p\t\p\.\c set `sum \c\p\t\p\.\c` sum=$1 case $sum in 62900) :;; *) echo 'Bad sum in '\c\p\t\p\.\c >&2 esac echo Extracting \r\a\w\t\p\.\c sed 's/^X//' > \r\a\w\t\p\.\c << '+ END-OF-FILE '\r\a\w\t\p\.\c X/* This file is part of the magtape handling package MAG. X Written by Dick Grune, Vrije Universiteit, Amsterdam. X*/ X X/* X * Name: rawtp, read raw tape X * Version: 820314 X * X Selected portions are read from tape and written to files. X X*/ X X#define MSGUSE "Usage is: rawtp [-cfhlmx] XX [ param ... ]" X X#include <stdio.h> X#include "aux.h" X#include "tp.h" X X#define TRUE 1 X#define FALSE 0 X#define EOS '\0' X X#define EOB 0 /* End Of Block */ X#define EOX -1 /* End Of File (to avoid confusion with EOF) */ X#define EOT -2 /* End Of Tape */ X#define AT_EOB (ilength <= EOB) X#define AT_EOX (ilength <= EOX) X#define AT_EOT (ilength <= EOT) X Xchar name [128]; Xchar *eoname = &name[0]; XFILE *ofile = NULL; X XTPFILE *tape; Xint unit = 0; Xchar *nmdns = TP_DENN; Xchar *rx = "r"; Xchar buff[TP_MAXB]; X Xchar *strins(); X Xmain(argc, argv) X char **argv; X{ X extern int ilength; X X argc--, argv++; X while (argc > 0 && argv[0][0] == '-') { X char *pp = argv[0]; X X while (*++pp) { X switch (*pp) { X /* insert cases to handle the standard options */ X#include "options.h" X /* special options */ X case 'x': X rx = "rx"; X break; X } X } X argc--, argv++; X } X if (argc < 1) X goto Lbad; X if (**argv == '+' || **argv == '-') X goto Lbad; X set_name(argv); X argc--, argv++; X X ilength = EOT; /* fake empty tape to test parameters */ X params(argc, argv); X X tperrout(stdout); X tape = tpopen(unit, nmdns, rx); X ilength = EOB; /* and now for keeps */ X skipIRG(); X params(argc, argv); X tpclose(tape); X exit(0); X XLbad: X error(MSGUSE, ""); X exit(1); X} X Xset_name(argv) X char **argv; X{ X register char *pt; X X eoname = strins(eoname, *argv); X eoname = strins(eoname, "01aaa01"); X *eoname = EOS; X for (pt = eoname; pt > name; pt--) X if (pt[-1] == '/') break; X if (eoname - pt > 14) X error("%s: file name too long", name); X} X Xparams(argc, argv) X char **argv; X{ X VOID(strins(eoname-7, "01")); X if (!argc) X param("+1x"); X else X while (argc--) { X param(*argv++); X incr(eoname-6); X } X} X Xchar *ppar; /* parameter being processed */ X Xparam(arg) X char *arg; X{ X register int repl; X X ppar = arg; X repl = getxrepl(ppar); X if (repl == 0) repl--; X VOID(strins(eoname-5, "aaa")); X while (repl-- && instr()) X incr(eoname-3); X} X Xint moved; X Xint Xinstr() { X char *p = ppar; X X moved = FALSE; X VOID(strins(eoname-2, "01")); X while (simp_instr(&p)) X incr(eoname-1); X return moved; X} X Xint copy = FALSE; X Xint Xsimp_instr(pp) X char **pp; X{ X register int cnt; X X switch (**pp) { X case EOS: X case 'x': X return FALSE; X case '+': X copy = TRUE; X break; X case '-': X copy = FALSE; X break; X default: X error("%s: bad parameter", ppar); X } X (*pp)++; X cnt = getint(pp); X while (cnt-- && copyfile()) { X } X if (**pp == '.') X (*pp)++; X cnt = getint(pp); X while (cnt-- && copyblock()) { X } X if (**pp == '.') X (*pp)++; X cnt = getint(pp); X while (cnt-- && copychar()) { X } X if (copy) X dropfile(); X return TRUE; X} X Xint ilength; X X/* ilength contains the number of characters the tape is ahead of the user; X * or it is EOX or EOT X */ Xchar *iptr; X Xint Xcopyfile() { X X if (AT_EOT) X return FALSE; X while (copyblock()) {} X skipTM(); X return TRUE; X} X Xint Xcopyblock() { X X if (AT_EOX) X return FALSE; X if (!copy) X ilength = EOB; X else X while (copychar()) {} X skipIRG(); X return TRUE; X} X Xint Xcopychar() { X X if (AT_EOB) X return FALSE; X outchar(*iptr); X iptr++; X ilength--; X return TRUE; X} X Xoutchar(c) { X X if (!copy) X return; X if (ofile == NULL) { X getfile(); X moved = TRUE; X } X putc(c, ofile); X} X X/* physical tape movers */ X XskipTM() { X X if (AT_EOT) X return; X ilength = EOB; X skipIRG(); X} X XskipIRG() { X int size; X X if (AT_EOX) X return; X size = tpread(tape, buff, TP_MAXB); X ilength = size < 0 ? EOT : size == 0 ? EOX : size; X iptr = buff; X if (!AT_EOT) X moved = TRUE; X} X X/* output file registration */ X Xgetfile() { X X if ((ofile = fopen(name, "w")) == NULL) X error("%s: cannot create", name); X} X Xdropfile() { X X if (ofile != NULL) { X VOID(fclose(ofile)); X ofile = NULL; X } X} X X/* service routines */ X Xchar * Xstrins(s1, s2) X char *s1, *s2; X{ X while (*s2 != EOS) X *s1++ = *s2++; X return s1; X} X Xint Xgetint(pp) X char **pp; X{ X register int val, res = 0; X X for (;;) { X val = **pp - '0'; X if (val < 0 || val > 9) X return res; X (*pp)++; X res = res*10 + val; X } X} X Xincr(p) X char *p; X{ X (*p)++; X if (*p == '9' + 1) { X *p = '0'; X incr(p-1); X } X else X if (*p == 'z' + 1) { X *p = 'a'; X incr(p-1); X } X} X Xint Xgetxrepl(p) X char *p; X{ X register int r; X X while (*p != 'x') X if (!*p++) X return 1; X p++; X r = getint(&p); X if (*p) X error("%s: bad replicator", p); X return r; X} X Xerror(p1, p2) X char *p1, *p2; X{ X printf(p1, p2); X printf("\n"); X exit(1); X} + END-OF-FILE rawtp.c chmod 'u=rw,g=r,o=r' \r\a\w\t\p\.\c set `sum \r\a\w\t\p\.\c` sum=$1 case $sum in 43915) :;; *) echo 'Bad sum in '\r\a\w\t\p\.\c >&2 esac echo Extracting \s\u\r\v\e\y\.\c sed 's/^X//' > \s\u\r\v\e\y\.\c << '+ END-OF-FILE '\s\u\r\v\e\y\.\c X/* This file is part of the magtape handling package MAG. X Written by Dick Grune, Vrije Universiteit, Amsterdam. X*/ X X/* X * Name: survey, survey contents of magtape X * Version: 820314 X */ X X#define MSGUSE "Usage is: survey [-cfhlmpx]\n" X X#include <stdio.h> X#include "aux.h" X#include "tp.h" X#include "etoa.h" X X#define WIDTH 64 X Xint unit = 0; Xchar *nmdns = TP_DENN; Xchar *rx = "r"; XTPFILE *tf; Xchar buff[TP_MAXB]; Xint size; X Xchar pflag = 0; X Xmain(argc, argv) X char *argv[]; X{ X argc--, argv++; X while (argc > 0 && argv[0][0] == '-') { X char *pp = argv[0]; X X while (*++pp) { X switch (*pp) { X /* insert cases to handle the standard options */ X#include "options.h" X /* special options */ X case 'p': X pflag = 1; X break; X case 'x': X rx = "rx"; X break; X } X } X argc--, argv++; X } X X if (argc != 0) X goto Lbad; X X tf = tpopen(unit, nmdns, rx); X X while ((size = tpread(tf, buff, TP_MAXB)) >= 0) { X printf("%6d", size); X if (pflag) X expose(); X printf("\n"); X } X exit(0); X XLbad: X fprintf(stderr, MSGUSE); X exit(1); X} X Xint Xhex(ch) { X return "0123456789ABCDEF"[ch&017]; X} X Xint Xprintable(ch) X char ch; X{ X int i = char2int(ch); /* 8 bits only */ X X return is_ascii95(i) ? i : '?'; X} X Xexpose() { X if (size == 0) X printf("\t* * * TAPE MARK * * *\n"); X else { X int i; X printf("\t"); X for (i = 0; i < WIDTH && i < size; i++) { X printf("%c", printable(buff[i])); X } X printf("\n EBC:\t"); X for (i = 0; i < WIDTH && i < size; i++) { X printf("%c", printable(ebc2asc(buff[i]))); X } X printf("\n HEX:\t"); X for (i = 0; i < WIDTH/2 && i < size; i++) { X char ch = buff[i]; X printf("%c%c", hex(ch>>4), hex(ch)); X } X printf("\n"); X } X} X + END-OF-FILE survey.c chmod 'u=rw,g=r,o=r' \s\u\r\v\e\y\.\c set `sum \s\u\r\v\e\y\.\c` sum=$1 case $sum in 22800) :;; *) echo 'Bad sum in '\s\u\r\v\e\y\.\c >&2 esac echo Extracting \N\O\S\s\p\l\i\t\.\c sed 's/^X//' > \N\O\S\s\p\l\i\t\.\c << '+ END-OF-FILE '\N\O\S\s\p\l\i\t\.\c X/* This file is part of the magtape handling package MAG. X Written by Dick Grune, Vrije Universiteit, Amsterdam. X*/ X X/* X * Name: NOSsplit, split Cyber system tape (data format is SI) X * Version: 820314 X */ X X#define MSGUSE "Usage is: NOSsplit [-cfhlm[s N]] [out_name]\n" X X#include <stdio.h> X#include "aux.h" X#include "tp.h" Xextern char *sprintf(); X X#define MINSIZE 6 /* smaller is a noise block */ X#define BSIZE 3840 /* blocksize binary files */ X#define CSIZE 960 /* blocksize coded files */ X#define SIZE 3840 /* maximum blocksize */ X#define EORM "\055\023\035\052\027\054\000" X#define EORL 7 X#define EOS '\0' X X#define lastblock(n) ((n)!=BSIZE && (n)!=CSIZE) X#define cybln(n) ((n)*8/60*10) X Xint fnumber = 0; Xchar *ofil = "x"; Xchar fname[128]; XFILE *outf; X Xchar buff[SIZE]; Xint size; /* number of chars in `buff' */ Xint bpos; /* number of bits consumed by `get6bits' */ Xint bstat; X Xint unit = 0; Xint skipf = 0; /* number of logical records to skip (forwards) */ Xchar *nmdns = TP_DENN; XTPFILE *tf; X Xchar *progname; X Xmain(argc, argv) X char *argv[]; X{ X progname = argv[0]; X argc--, argv++; X X while (argc > 0 && argv[0][0] == '-') { X char *pp = argv[0]; X X while (*++pp) { X switch (*pp) { X /* insert cases to handle the standard options */ X#include "options.h" X /* special options */ X case 's': X if (argc < 2) X goto Lbad; X if (!is_digit(argv[1][0])) X goto Lbad; X skipf = atoi(argv[1]); X argc--, argv++; X break; X } X } X argc--, argv++; X } X X if (argc == 1) { X ofil = argv[0]; X argc--, argv++; X } X X if (argc != 0) X goto Lbad; X X read_tape(); X exit(0); X XLbad: X fprintf(stderr, MSGUSE); X exit(1); X X} X Xread_tape() { X int i; X int bcnt; X X tperrout(stdout); X tf = tpopen(unit, nmdns, "rx"); X X fillbuff(); X if (size == 80 && strncmp(buff, "VOL1", 4) == 0) { X printf("This is a labelled tape\n"); X printf("For label information use `ansir -pn'\n"); X while (size > 0) X fillbuff(); X if (size == 0) X fillbuff(); X } X else printf("This is a non-labelled tape\n"); X X for (i = 0; i < skipf; i++) { X if (size <= 0) { X printf("%d record%s missing\n", english(skipf-i)); X exit(1); X } X fnumber++; X while (!lastblock(size)) X fillbuff(); X fillbuff(); X } X X if (skipf > 0) X printf("%d logical record%s skipped\n", english(skipf)); X X while (size > 0) { X newcreat(fnumber++); X X bcnt = 1; X while (putbuff(cybln(size)), !lastblock(size)) { X fillbuff(); X bcnt++; X } X X proc_eor(bcnt); X X VOID(fclose(outf)); X outf = NULL; X fillbuff(); X } X X printf("%d record%s retrieved\n", english(fnumber-skipf)); X} X Xnewcreat(fn) { X int i; X X for (i=0; ofil[i] != EOS; i++) X fname[i] = ofil[i]; X VOID(sprintf(&fname[i], "%04d", fn)); X outf = fopen(fname, "w"); X if (outf == NULL) { X printf("%s: cannot create `%s'\n", progname, fname); X exit(1); X } X} X Xfillbuff() { X X do size = tpread(tf, buff, sizeof buff); X while (size > 0 && size < MINSIZE /* noise record */); X bpos = bstat = 0; X} X Xputbuff(n) X int n; /* number of 6bit chars */ X{ X X while (n-- > 0) X putc(get6bits(), outf); X} X X Xproc_eor(bcnt) { X char eor[EORL]; X int i; X X for (i = 0; i < EORL; i++) X eor[i] = get6bits(); X X printf("%s: ", fname); X printf("%d block%s, ", english(bcnt)); X if (strncmp(eor, EORM, EORL) != 0) X printf("no proper EOR\n"); X else X printf("EOR%2o\n", get6bits()); X} X X#define left(c,n) (((c)&((077<<(8-(n)))&0377))>>(8-(n))) X#define right(c,n) (((c)&((077>>(6-(n)))&0377))<<(6-(n))) X/* X * These forms are constructed through program transformations; the X * author cannot, by any stretch of imagination, guess why they work. X */ X Xint Xget6bits() { X int res = 0; X X switch (bstat++) { X case 0: res = left(buff[bpos+0], 6); X break; X case 1: res = right(buff[bpos+0], 2) + left(buff[bpos+1], 4); X break; X case 2: res = right(buff[bpos+1], 4) + left(buff[bpos+2], 2); X break; X case 3: res = right(buff[bpos+2], 6); X break; X } X if (bstat == 4) { X bpos += 3; X bstat = 0; X } X return res; X} + END-OF-FILE NOSsplit.c chmod 'u=rw,g=r,o=r' \N\O\S\s\p\l\i\t\.\c set `sum \N\O\S\s\p\l\i\t\.\c` sum=$1 case $sum in 08337) :;; *) echo 'Bad sum in '\N\O\S\s\p\l\i\t\.\c >&2 esac echo Extracting \N\O\S\t\r\.\c sed 's/^X//' > \N\O\S\t\r\.\c << '+ END-OF-FILE '\N\O\S\t\r\.\c X/* This file is part of the magtape handling package MAG. X Written by Dick Grune, Vrije Universiteit, Amsterdam. X*/ X X/* X * Program: NOStr, translates a Cyber 6-bit file into a UNIX ASCII file. X * Version: 820314 X */ X X#define MSGUSE "Usage is: NOStr -C [file]" X X#include <stdio.h> X#include "aux.h" X X#define MAXERR 40 X#define EOS '\0' X XFILE *ifile; /* input file */ Xchar *iname; /* input name */ X Xint displZ(), asciiZ(), binary(); Xstruct conv { X char *name; X int (*command)(); X char *expl; X} conv[] = { X {"d", displZ, "Z-type records in DISPLAY code"}, X {"a", asciiZ, "Z-type records in ASCII95"}, X {"b", binary, "binary, = ASCII256"} X}; X Xmain(argc, argv) X char *argv[]; X{ X int p; X X if (argc < 2 || argc > 3 || argv[1][0] != '-' || strlen(argv[1]) != 2) X goto Bad_usage; X if (argc == 2 || strcmp(argv[2], "-") == 0) { X iname = "standard input"; X ifile = stdin; X } X else { X iname = argv[2]; X ifile = fopen(iname, "r"); X if (ifile == NULL) { X fprintf(stderr, "%s: cannot open %s\n", X argv[0], iname); X exit(1); X } X } X for (p = 0; p < n_items(conv); p++) X if (strcmp(&argv[1][1], conv[p].name) == 0) { X (*conv[p].command)(); X exit(0); X } XBad_usage: X fprintf(stderr, MSGUSE); X fprintf(stderr, X "\nwhere the conversion code C is one of the following:\n"); X for (p = 0; p < n_items(conv); p++) X fprintf(stderr, "`%s': %s\n", conv[p].name, conv[p].expl); X exit(1); X} X X#define NL '\n' X#define TEN 10 X Xint cwrd[TEN]; Xlong lcnt = 1; Xlong icnt = 0; X XdisplZ() { /* recognize Z-type records in DISPLAY code */ X int nch; X int zpend = 0; X X while (nch = get_cwrd(TEN), nch != 0) { X int i; X X if (nch != TEN) X VOID(complain("short word", 0)); X while (nch != 0 && cwrd[nch-1] == 0) X nch--; X if (zpend && nch > 0) X putdispl(0); /* zero pending */ X for (i = 0; i < nch; i++) X putdispl(cwrd[i]); X if (nch < TEN-1) X putascii(NL); X zpend = nch == TEN-1; X } X} X X#define FIVE 5 X XasciiZ() { /* recognize Z-type records in ASCII95 */ X int nch; X X while (nch = get_cwrd(FIVE), nch != 0) { X int i; X X if (nch != FIVE) X VOID(complain("short word", 0)); X while (nch != 0 && cwrd[nch-1] == 0) X nch--; X for (i = 0; i < nch; i++) X putascii(cwrd[i]); X if (nch < FIVE) X putascii(NL); X } X} X Xbinary() { /* binary, also ASCII256 */ X int ch; X X while (ch = get12bits(), ch != EOF) X putascii(ch); X} X Xint Xget_cwrd(n) { /* gather n (60/n)-bit bytes into a Cyber word */ X int i; X X for (i = 0; i < n; i++) { X cwrd[i] = n == TEN ? get6bits() : X n == FIVE ? get12bits() : (abort(), 0); X if (cwrd[i] == EOF) X break; X } X return i; X} X Xint Xget12bits() { X int ch1, ch2; X static errcnt = 0; X X ch1 = get6bits(); X if (ch1 == EOF) X return EOF; X ch2 = get6bits(); X if (ch2 == EOF) X ch2 = 0; X X ch1 = (ch1 << 6) + ch2; X if (ch1 >> 8) X errcnt = complain("composed char wider than 8 bits", errcnt); X return ch1; X} X Xint Xget6bits() { X int ch = getc(ifile); X static errcnt = 0; X X if (ch == EOF) X return EOF; X icnt++; X if (ch >> 6) X errcnt = complain("input char wider than 6 bits", errcnt); X return ch; X} X Xputdispl(ch) { /* convert display to ASCII */ X putchar( X "%ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+-*/()$= ,.#[]:\"_!&'?<>@\\^;" X [ch]); X} X Xputascii(ch) X char ch; X{ X putchar(ch); X if (ch == NL) X lcnt++; X} X Xint Xcomplain(s, n) X char *s; X{ X if (n > MAXERR) X return n; X fprintf(stderr, X "At input char %ld, at output line %ld, %s in file `%s'\n", X icnt, lcnt, s, iname); X if (n == MAXERR) X fprintf(stderr, X "After %d complaints, further complaints of this type suppressed\n", X MAXERR); X return n+1; X} + END-OF-FILE NOStr.c chmod 'u=rw,g=r,o=r' \N\O\S\t\r\.\c set `sum \N\O\S\t\r\.\c` sum=$1 case $sum in 55112) :;; *) echo 'Bad sum in '\N\O\S\t\r\.\c >&2 esac exit 0 -- Rich $alz "Anger is an energy" Cronus Project, BBN Labs rsalz@bbn.com Moderator, comp.sources.unix sources@uunet.uu.net