========== archive program from chapter 3 ========== define(NAMESIZE,20) define(MAXFILES,5) define(TBL,LETT) define(PRINT,LETP) define(EXTR,LETX) define(UPD,LETU) define(DEL,LETD) common /carch/ fname(NAMESIZE,MAXFILES),fstat(MAXFILES),nfiles,errcnt character fname # file arguments integer fstat # YES if touched, NO otherwise; init = NO integer nfiles # number of file args integer errcnt # error count; init = 0 # acopy - copy size characters from fdi to fdo subroutine acopy(fdi, fdo, size) character getch character c integer fdi, fdo, i, size for (i = 1; i <= size; i = i + 1) { if (getch(c, fdi) == EOF) break call putch(c, fdo) $@$ return end # addfil - add file "name" to archive subroutine addfil(name, fd, errcnt) character head(MAXLINE), name(ARB) integer open integer errcnt, fd, nfd nfd = open(name, READ) if (nfd == ERR) { call putlin(name, ERROUT) call remark(": can't add.") errcnt = errcnt + 1 $@$ if (errcnt == 0) { call makhdr(name, head) call putlin(head, fd) call fcopy(nfd, fd) call close(nfd) $@$ return end # amove - move name1 to name2 subroutine amove(name1, name2) character name1(ARB), name2(ARB) integer create, open integer fd1, fd2 fd1 = open(name1, READ) if (fd1 == ERR) call cant(name1) fd2 = create(name2, WRITE) if (fd2 == ERR) call cant(name2) call fcopy(fd1, fd2) return end # archive - file maintainer character aname(NAMESIZE) integer getarg integer comand(2) if (getarg(1, comand, 2) == EOF | getarg(2, aname, NAMESIZE) == EOF) call help call getfns if (comand(1) == UPD) call update(aname) else if (comand(1) == TBL) call table(aname) else if (comand(1) == EXTR | comand(1) == PRINT) call extrac(aname, comand(1)) else if (comand(1) == DEL) call delete(aname) else call help stop end # block data for archive block data include carch data errcnt /0/ end # delete - delete files from archive subroutine delete(aname) character aname(NAMESIZE), in(MAXLINE) integer create, open integer afd, tfd include carch # string tname "archtemp" integer tname(9) data tname(1), tname(2), tname(3), tname(4)/LETA, LETR, LETC, LETH/ data tname(5), tname(6), tname(7), tname(8)/LETT, LETE, LETM, LETP/ data tname(9)/EOS/ if (nfiles <= 0) # protect innocents call error("delete by name only.") afd = open(aname, READWRITE) if (afd == ERR) call cant(aname) tfd = create(tname, READWRITE) if (tfd == ERR) call cant(tname) call replac(afd, tfd, DEL, errcnt) call notfnd call close(afd) call close(tfd) if (errcnt == 0) call amove(tname, aname) else call remark("fatal errors - archive not altered.") call remove(tname) return end # extrac - extract files from archive subroutine extrac(aname, cmd) character aname(NAMESIZE), ename(NAMESIZE), in(MAXLINE) integer create, filarg, gethdr, open integer afd, cmd, efd, size include carch afd = open(aname, READ) if (afd == ERR) call cant(aname) if (cmd == PRINT) efd = STDOUT else efd = ERR while (gethdr(afd, in, ename, size) ~= EOF) if (filarg(ename) == NO) call fskip(afd, size) else { if (efd ~= STDOUT) efd = create(ename, WRITE) if (efd == ERR) { call putlin(ename, ERROUT) call remark(": can't create.") errcnt = errcnt + 1 call fskip(afd, size) $@$ else { call acopy(afd, efd, size) if (efd ~= STDOUT) call close(efd) $@$ $@$ call notfnd return end # filarg - check if name matches argument list integer function filarg(name) character name(ARB) integer equal, getarg integer i include carch if (nfiles <= 0) { filarg = YES return $@$ for (i = 1; i <= nfiles; i = i + 1) if (equal(name, fname(1, i)) == YES) { fstat(i) = YES filarg = YES return $@$ filarg = NO return end # fsize - size of file in characters integer function fsize(name) character getch character c, name(ARB) integer open integer fd fd = open(name, READ) if (fd == ERR) fsize = ERR else { for (fsize = 0; getch(c, fd) ~= EOF; fsize = fsize + 1) ; call close(fd) $@$ return end # fskip - skip n characters on file fd subroutine fskip(fd, n) character getch character c integer fd, i, n for (i = 1; i <= n; i = i + 1) if (getch(c, fd) == EOF) break return end # getfns - get file names into fname, check for duplicates subroutine getfns integer equal, getarg integer i, j include carch errcnt = 0 for (i = 1; i <= MAXFILES; i = i + 1) if (getarg(i+2, fname(1, i), NAMESIZE) == EOF) break nfiles = i - 1 if (i > MAXFILES) if (getarg(i+2, j, 1) ~= EOF) call error("too many file names.") for (i = 1; i <= nfiles; i = i + 1) fstat(i) = NO for (i = 1; i < nfiles; i = i + 1) for (j = i + 1; j <= nfiles; j = j + 1) if (equal(fname(1, i), fname(1, j)) == YES) { call putlin(fname(1, i), ERROUT) call error(": duplicate file name.") $@$ return end # gethdr - get header info from fd integer function gethdr(fd, buf, name, size) character buf(MAXLINE), c, name(NAMESIZE), temp(NAMESIZE) integer ctoi, equal, getlin, getwrd integer fd, i, len, size # string hdr "-h-" integer hdr(4) data hdr(1),hdr(2),hdr(3),hdr(4)/MINUS,LETH,MINUS,EOS/ if (getlin(buf, fd) == EOF) { gethdr = EOF return $@$ i = 1 len = getwrd(buf, i, temp) if (equal(temp, hdr) == NO) call error("archive not in proper format.") gethdr = YES len = getwrd(buf, i, name) size = ctoi(buf, i) return end # getwrd - get non-blank word from in(i) into out, increment i integer function getwrd(in, i, out) integer in(ARB), out(ARB) integer i, j while (in(i) == BLANK | in(i) == TAB) i = i + 1 j = 1 while (in(i)~=EOS & in(i)~=BLANK & in(i)~=TAB & in(i)~=NEWLINE) { out(j) = in(i) i = i + 1 j = j + 1 $@$ out(j) = EOS getwrd = j - 1 return end # help - diagnostic printout subroutine help call error("usage: archive {dptux$@$ archname [files].") return end define(MAXCHARS,10) # makhdr - make header line for archive member subroutine makhdr(name, head) character head(MAXLINE), name(NAMESIZE) integer fsize, itoc, length integer i # string hdr "-h-" integer hdr(4) data hdr(1),hdr(2),hdr(3),hdr(4)/MINUS,LETH,MINUS,EOS/ call scopy(hdr, 1, head, 1) i = length(hdr) + 1 head(i) = BLANK call scopy(name, 1, head, i+1) i = length(head) + 1 head(i) = BLANK i = i + 1 + itoc(fsize(name), head(i+1), MAXCHARS) head(i) = NEWLINE head(i+1) = EOS return end # notfnd - print "not found" message subroutine notfnd integer i include carch for (i = 1; i <= nfiles; i = i + 1) if (fstat(i) == NO) { call putlin(fname(1, i), ERROUT) call remark(": not in archive.") errcnt = errcnt + 1 $@$ return end # replac - replace or delete files subroutine replac(afd, tfd, cmd, errcnt) character in(MAXLINE), uname(NAMESIZE) integer filarg, gethdr integer afd, cmd, errcnt, size, tfd while (gethdr(afd, in, uname, size) ~= EOF) if (filarg(uname) == YES) { if (cmd == UPD) # add new one call addfil(uname, tfd, errcnt) call fskip(afd, size) # discard old one $@$ else { call putlin(in, tfd) call acopy(afd, tfd, size) $@$ return end # table - print table of archive contents subroutine table(aname) character aname(NAMESIZE), in(MAXLINE), lname(NAMESIZE) integer filarg, gethdr, open integer afd, size afd = open(aname, READ) if (afd == ERR) call cant(aname) while (gethdr(afd, in, lname, size) ~= EOF) { if (filarg(lname) == YES) call tprint(in) call fskip(afd, size) $@$ call notfnd return end # tprint - print table entry for one member subroutine tprint(buf) character buf(ARB) call putlin(buf, STDOUT) return end # update - update existing files, add new ones at end subroutine update(aname) character aname(NAMESIZE) integer create, getarg, open integer afd, i, tfd include carch # string tname "archtemp" integer tname(9) data tname(1), tname(2), tname(3), tname(4)/LETA, LETR, LETC, LETH/ data tname(5), tname(6), tname(7), tname(8)/LETT, LETE, LETM, LETP/ data tname(9)/EOS/ afd = open(aname, READWRITE) if (afd == ERR) # maybe it's a new one afd = create(aname, READWRITE) if (afd == ERR) call cant(aname) tfd = create(tname, READWRITE) if (tfd == ERR) call cant(tname) call replac(afd, tfd, UPD, errcnt) # update existing for (i = 1; i <= nfiles; i = i + 1) # add new ones if (fstat(i) == NO) { call addfil(fname(1, i), tfd, errcnt) fstat(i) = YES $@$ call close(afd) call close(tfd) if (errcnt == 0) call amove(tname, aname) else call remark("fatal errors - archive not altered.") call remove(tname) return end