makecopy -- ファイルの動的作成 ― 2015年05月05日 08:42
ファイルを動的に作成できると、応用プログラムの幅が広がります。ここでファイルを動的に作成するfcreate()を紹介します。
fcreate()は、ファイルが存在しない時に作成し、作成できなかった場合はERRを返します。 WATCOM Fortran77版は下記の通り。この版は、ファイルを一度作成し閉じますので、作成したファイルを操作するには、再度オープンする必要があります。
C fcreate.for -- create file, file must be open once as write mode integer function fcreate(fn) integer*1 fn(81) ! NAMESIZE(81) integer uid integer fopen if (fopen(uid,fn,66) .ne. -1) then ! WRITE(LETW) ERR(-1) call fclose(uid) fcreate = 0 else fcreate = -1 ! ERR(-1) endif return end
これを利用したmakecopyを紹介します。これは、Windowsのcopyコマンドと似ています。
makecopy oldfile newfile
oldfile,newfileの指定がなかったら、プログラムは打ち切られます。
RATFOR版は下記の通り。
# makecopy.r4 -- copy one file to another character iname(NAMESIZE),oname(NAMESIZE) integer fcreate,fopen,getarg integer fin,fout call initfile if((getarg(1,iname,NAMESIZE) == ERR) | (getarg(2,oname,CNAMESIZE) == ERR)) call error('usage: makecopy input output.') if (fopen(fin,iname,READ) == ERR) call cant(iname) if (fcreate(oname) == ERR) call cant(oname) else if (fopen(fout,oname,WRITE) == ERR) then call cant(oname) endif call fcopy(fin,fout) call fclose(fin) call fclose(fout) stop endWATCOM Fortran77版は下記の通り。
c makecopy -- copy one file to another integer*1 iname(81),oname(81) ! NAMESIZE(81) integer fcreate,fopen,getarg integer fin,fout call initfile if((getarg(1,iname,81) .eq. -1) ! NAMESIZE(81) ERR(-1) 1 .or. (getarg(2,oname,81) .eq. -1)) then ! NAMESIZE(81) ERR(-1) call error('usage: makecopy input output.') end if if (fopen(fin,iname,82) .eq. -1) then ! ERR(-1) READ(LETR) call cant(iname) endif if (fcreate(oname) .eq. -1) then ! ERR(-1) call cant(oname) else if (fopen(fout,oname,87) .eq. -1) then ! WRTIE(LETW) ERR(-1) call cant(oname) endif call fcopy(fin,fout) call fclose(fin) call fclose(fout) stop end
archive -- ファイル書庫 ― 2015年05月17日 13:58
簡単な、ファイル書庫archiveを紹介します。
archive [dptux] archive-file file ... d-delete fileを削除する p-print fileを標準出力に書き出す t-table archive-fileの一覧を書き出す u-update fileを更新または追加する x-extract fileを取り出す
ファイル書庫の形式は以下のとおり。
file1 header file1 file2 header file2 . . .
file headerは、ファイル名、ファイル書庫内のファイル長さです(ファイルの実際の長さでないことに注意)。
archive本体から紹介します。
RATFOR版は下記の通り。
# archive.r4 -- file nameger character aname(NAMESIZE) integer getarg character comand(2) call initfile() if ((getarg(1,comand,2) == EOF) 1 | (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() end if stop end
何か間違いがあれば、helpテキストを表示します。 WATCOM Fortran77版は、下記の通り。
c archive -- file nameger program archive integer*1 aname(81) ! NAMESIZE(81) integer getarg integer*1 comand(2) call initfile() if ((getarg(1,comand,2) .eq. -1) ! ERR(-1) 1 .or. (getarg(2,aname,81) .eq. -1)) then ! NAMESIZE(81) ERR(-1) call help() end if call getfns() if (comand(1) .eq. 117) then ! UPD(LETU) call update(aname) else if (comand(1) .eq. 116) then ! TBL(LETT) call table(aname) else if ((comand(1) .eq. 120) ! EXTR(LETE) 1 .or. (comand(1) .eq. 112)) then ! PRINT(LETP) call extrac(aname,comand(1)) else if (comand(1) .eq. 100) then ! DEL(LETD) call delete(aname) else call help() end if stop end
ヘルプを書き出すhelp()サブルーチンは下記の通り。
RATFOR版。
# help.r4 -- diagnostic printout subroutine help call error('usage: archive { dptux } archname [files].') return end
WATCOM Fortran77版。
c help.for -- diagnostic printout subroutine help call error('usage: archive { dptux } archname [files].') return end
コマンドラインの引数のうちfile名を処理するgetfns()サブルーチンを示します。このサブルーチンは、引数にあるファイル名を取り出し、重複がないか確認し、処理フラグをリセットします。
RATFOR版は次の通り。
# getfns.r -- get file names into fname, check for duplicates subroutine getfns integer equal,getarg integer i,j integer*1 junk(2) include carch.ri 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,junk,2) != EOF) call error('too many files.') 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
WATCOMM Fortran77版は下記の通り。
c getfns.f -- get file names into fname, check for duplicates subroutine getfns integer equal,getarg integer i,j integer*1 junk(2) include carch.fi errcnt = 0 i = 1 while ( i .le. 20 ) do ! MAXFILES(20) if (getarg(i+2,fname(1,i),81) .eq. -1) then ! NAMESIZE(81) ERR(-1) exit end if i = i + 1 end while nfiles = i - 1 if (i .gt. 20) then ! MAXFILES(20) if (getarg(i+2,junk,2) .ne. -1) then ! ERR(-1) call error('too many files.') end if end if i = 1 while (i .le. nfiles) do fstat(i) = 0 ! NO(0) i = i + 1 end while i = 1 while (i .lt. nfiles) do j = i + 1 while (j .le. nfiles) do if (equal(fname(1,i),fname(1,j)) .eq. 1) then ! YES(1) call putlin(fname(1,i),6) ! ERROUT(6) call error(': duplicate file name.') end if j = j + 1 end while i = i + 1 end while return end
いずれの版でも、commonファイルをインクルードします。ファイルのインクルードには、先に作ったincludeを使います。インクルードされるファイルは以下の通り。
RATFOR版。
# carch.ri -- common definiton of archive 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 arguments integer errcnt ! error count; init = 0
WATCOM Fortran77版。
c carch.fi -- common definiton of archive common /carch/fname(81,20),fstat(20),nfiles,errcnt integer*1 fname ! file arguments integer fstat ! YES if touched, NO otherwise; init = NO integer nfiles ! number of file arguments integer errcnt ! error count; init = 0
その他の下請けルーチンについては次回説明します。
update() -- ファイルの追加更新 ― 2015年05月24日 20:21
archiveのファイルの追加、更新を受け持つupdatre()を紹介します。
update()は、replac()で書庫の内容を一時ファイルに書き写し、その後、 指定されたファイルすべてについて、addfil()でファイルを追加します。 最後に、一連の処理でエラーがなければ、amove()で書庫を一時ファイルで上書きします。
update()のRATFOR版は以下の通り。
# update.f -- update existing files, add new ones at end subroutine update(aname) character aname(NAMESIZE) integer fcreate,fopen integer afd,i,tfd include carch.ri string tname "archtemp" if (fopen(afd,aname,READWRITE) == ERR) if (fcreate(aname) == ERR) call cant(aname) afd = fopen(afd,aname,READWRITE) if (fcreate(tname) == ERR) call cant(tname) if (fopen(tfd,tname,READWRITE) == ERR) call cant(tname) call replac(afd,tfd,UPD,errcnt) for (i = 1; i <= nfiles; i = i + 1) if (fstat(i) == NO) { call addfil(fname(1,i),tfd,errcnt) fstat(i) = YES } call fclose(afd) call fclose(tfd) if (errcnt == 0) then call amove(tname,aname) else call remark('fatal errors - archive not altered.') call fremove(tname) return end
WATCOM fortran77版は、以下の通り。
c update.f -- update existing files, add new ones at end subroutine update(aname) integer*1 aname(81) ! NAMESIZE(81) integer fcreate,fopen integer afd,i,tfd include carch.fi integer*1 tname(9) data tname/'a','r','c','h','t','e','m','p',-2/ if (fopen(afd,aname,66) .eq. -1) then ! READWRITE(LETB) ERR(-1) ! maybe it's new one if (fcreate(aname) .eq. -1) then ! ERR(-1) call cant(aname) endif afd = fopen(afd,aname,66) ! READWRITE(LETB) endif if (fcreate(tname) .eq. -1) then ! ERR(-1) call cant(tname) else if (fopen(tfd,tname,66) .eq. -1) then ! READWRITE(LETB) ERR(-1) call cant(tname) end if call replac(afd,tfd,117,errcnt) ! UPD(LETU) i = 1 while (i .le. nfiles) do if (fstat(i) .eq. 0) then ! NO(0) call addfil(fname(1,i),tfd,errcnt) fstat(i) = 1 ! YES(1) end if i = i + 1 end while call fclose(afd) call fclose(tfd) if (errcnt .eq. 0) then call amove(tname,aname) else call remark('fatal errors - archive not altered.') endif call fremove(tname) return end
update()の中で、fremove()はfcreate()の逆で、ファイルを削除します。 fremove()は下記の通り。
c fremove.for -- remove a file, file must be open once as read mode subroutine fremove(fn) integer*1 fn(81) ! NAMESIZE(81) integer uid integer fopen uid = fopen(uid,fn,82) ! READ(LETR) close(unit=uid,status='delete') return end
amove()のRATFOR版は下記の通り。
# amove.r4 -- move name1 to name2 subroutine amove(name1,name2) character name1(ARB),name2(ARB) integer fd1,fd2 integer fopen,fcreate if (fopen(fd1,name1,READ) == ERR) call cant(name1) if (fcreate(name2) == ERR) call cant(name2) if (fopen(fd2,name2,WRITE) == ERR) call cant(name2) call fcopy(fd1,fd2) call fclose(fd1) call fclose(fd2) return end
WATCOM fortran77版は下記の通り。
c amove.for -- move name1 to name2 subroutine amove(name1,name2) integer*1 name1(*),name2(*) ! ARB(*) integer fd1,fd2 integer fopen,fcreate if (fopen(fd1,name1,82) .eq. -1) then ! READ(LETR) ERR(-1) call cant(name1) end if if (fcreate(name2) .eq. -1) then ! ERR(-1) call cant(name2) end if if (fopen(fd2,name2,87) .eq. -1) then ! WRITE(LETW) ERR(-1) call cant(name2) end if call fcopy(fd1,fd2) call fclose(fd1) call fclose(fd2) return end
addfil()は、指定されたファイルを開け、ヘッダーを作り、一時ファイルに 追加します。
RATFOR版は下記の通り。
# addfil.r4 -- add file name to erchive subroutine addfil(name,fd,errcnt) character name(ARB) integer fd,errcnt character head(MAXLINE) integer fopen,nfd if (fopen(nfd,name,READ) { call putlin(nale,ERROUT) call remark(': can not add.') errcnt = errcnt + 1 } if (errcnt == 0) { call makhdr(name,head) call putlin(head,fd) call fcopy(nfd,fd) call fclose(nfd) } return end
WATCOM Fortran77版は下記の通り。
c addfil.for -- add file name to erchive subroutine addfil(name,fd,errcnt) integer*1 name(*) ! ARB(*) integer fd,errcnt integer*1 head(81) ! MAXLINE(81) integer fopen,nfd if (fopen(nfd,name,82) .eq. -1) then ! READ(LETR) ERR(-1) call putlin(name,6) ! ERROUT(6) call remark(': can not add.') errcnt = errcnt + 1 end if if (errcnt .eq. 0) then call makhdr(name,head) call putlin(head,fd) call fcopy(nfd,fd) call fclose(nfd) end if return end
ヘッダーを作るのは、makhdr()が行います。
RATFOR版は下記の通り。
# makhdr.r4 -- make header line for archive member subroutine makhdr(name,head) character name(NAMESIZE),head(MAXLINE) integer fsize,itoc,length integer i string hdr "-h-" 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
WATCOM Fortran77版は下記の通り。
c makhdr.for -- make header line for archive member subroutine makhdr(name,head) integer*1 name(81),head(81+1) ! NAMESIZE(81) MAXLINE(81) integer fsize,itoc,length integer i integer*1 hdr(4) data hdr/'-','h','-',-2/ call scopy(hdr,1,head,1) i = length(hdr) + 1 head(i) = 32 ! BLANK(32) call scopy(name,1,head,i+1) i = length(head) + 1 head(i) = 32 ! BLANK(32) i = i + 1 + itoc(fsize(name),head(i+1),81) ! MAXCHARS(81) head(i) = 10 ! NEWLINE(10) head(i+1) = -2 ! EOS(-2) return end
scopy()は、文字列をコピーします。
RATFOR版は、下記の通り。
# scopy.r4 -- copy string at from(i) to to(j) subroutine scopy(from,i,to,j) character from(ARB),to(ARB) integer i,j integer k1,k2 k2 = j for (k1 = i; from(k1) != EOS; k1 = k1 +1) { to(k2) = from(k1) k2 = k2 + 1 } to(k2) = EOS return end
WATCOM Fortran77版は、下記の通り。
c scopy.for -- copy string at from(i) to to(j) subroutine scopy(from,i,to,j) integer*1 from(*),to(*) ! ARB(*) integer i,j integer k1,k2 k2 = j k1 = i while (from(k1) .ne. -2) do ! EOF(-2) to(k2) = from(k1) k2 = k2 + 1 k1 = k1 + 1 end while to(k2) = -2 ! EOS(-2) return end
fsize()はファイルの文字数(ファイルのサイズではないことに注意)を 計算します。
RATFOR版は下記の通り。
# fsize.r4 -- size of file in characters integer function fsize(name) character name(ARB) character fgetc,c integer fd,fopen if (fopen(fd,name,READ) == ERR) fsize = ERR else { fsize = 0 while (fgetc(fd,c) != EOF) fsize = fsize + 1 call fclose(fd) } return end
WATCOM Fortran77版は下記の通り。
c fsize.for -- size of file in characters integer function fsize(name) integer*1 name(*) ! ARB(*) integer*1 fgetc,c integer fd,fopen if (fopen(fd,name,82) .eq. -1) then ! READ(LETR) ERR(-1) fsize = -1 ! ERR(-1) else fsize = 0 while (fgetc(fd,c) .ne. -1) do ! EOF(-1) fsize = fsize + 1 end while call fclose(fd) end if return end
次回は、ほかの機能について説明します。
table() -- ファイル情報の書き出し ― 2015年05月30日 15:19
ファイルの内容見出しの手続きtable()を紹介します。
table()は、書庫を開き、書庫内の各ファイルについて、引数のファイルと一致する ならば、ファイル情報を書き出します。
table()のRATFOR版は以下の通り。
# table.r4 -- print table of archive contents subroutine table(aname) integer*1 aname(NAMESIZE) integer*1 in(MAXLINE),lname(NAMESIZE) integer filarg,fopen,gethdr integer afd,size,i if (fopen(afd,aname,82) == ERR) call cant(aname) while (gethdr(afd,in,lname,size) != EOF) { if (filarg(lname) == YES) call tprint(lname) call fskip(afd,size) } call notfnd return end
WATCOM fortran77版は、以下の通り。
c table.for -- print table of archive contents subroutine table(aname) integer*1 aname(81) ! NAMESIZE(81) integer*1 in(81),lname(81) ! MAXLINE(81) NAMESIZE(81) integer filarg,fopen,gethdr integer afd,size if (fopen(afd,aname,82) .eq. -1) then ! READ(LETR) ERR(-1) call cant(aname) end if while (gethdr(afd,in,lname,size) .ne. -1) do ! EOF(-1) if (filarg(lname) .eq. 1) then ! YES(1) call tprint(lname) endif call fskip(afd,size) end while call notfnd return end
tprint()は、ヘッダーから必要項目、ファイル名とサイズを書き出します。
RATFOR版は下記の通り。
# tprint.r4 -- print table entry for one member subroutine tprint(buf) character buf(ARB) call putlin(buf,STDOUT) call putc(NEWLINE) return end
WATCOM Fortran77版は下記の通り。
c tprint.for -- print table entry for one member subroutine tprint(buf) integer*1 buf(*) ! ARB(*) call putlin(buf,6) ! STDOUT(6) call putc(10) ! NEWLINE(10) return end
ヘッダーを取り出すのは、gethdr()です。 書庫ファイルの終わりに達した時はEOFを返します。
RATFOR版は下記の通り。
# gethdr.r4 -- get header into from fd integer function gethdr(fd,buf,name,size) integer fd,i,len,size character buf(MAXLINE),name(NAMESIZE),temp(NAMESIZE) integer getlin,getwrd,ctoi,equal string hdr "-h-" if (getlin(buf,fd) == EOF) { gethdr = NO return } i = 1 len = getwrd(buf,i,temp) if (equal(temp,hdr) == YES) call error('archive not in proper format.') gethdr = YES len = getwrd(buf,i,name) size = ctoi(buf,i) return end
WATCOM Fortran77版は下記の通り。
c gethdr.for -- get header into from fd integer function gethdr(fd,buf,name,size) integer fd,size integer*1 buf(81),name(81),temp(81) ! MAXLINE(81) NAMESIZE(81) integer getlin,getwrd,ctoi,equal integer*1 hdr(4) data hdr/'-','h','-',-2/ if (getlin(buf,fd) .eq. -1) then ! EOF(-1) gethdr = -1 ! EOF(-1) return end if i = 1 len = getwrd(buf,i,temp) if (equal(temp,hdr) .eq. 0) then ! NO(0) call error('archive not in proper format.') end if gethdr = 1 ! YES(1) len = getwrd(buf,i,name) size = ctoi(buf,i) return end
fskip()は、ファイルfdをn文字読みどばします。
RATFOR版は下記の通り。
# fskip.r4 -- skip n characters on the fd subroutine fskip(fd,n) integer fd,n character fgetc,c integer i for (i = 1;i <= n; i = i + 1) if (fgetc(fd,c) == EOF) break return end
WATCOM Fortran77版は下記の通り。
c fskip.for -- skip n characters on the fd subroutine fskip(fd,n) integer fd,n integer*1 fgetc,c integer i,junk i = 1 while (i .le. n) do if (fgetc(fd,c) .eq. -1) then ! EOF(-1) exit end if i = i + 1 end while return end
filarg()は書庫から取り出したファイル名が引数にあるかどうかを 判断します。ただし、引数がない場合は常にありと判断します。
RATFOR版は下記の通り。
# filarg.r -- check if name maches argument list integer function filarg(name) character name(ARB) integer equal,i include carch.fi if (nfiles <= 0) then filarg = YES return end if 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
WATCOM Fortran77版は下記の通り。
c filarg.f -- check if name maches argument list integer function filarg(name) integer*1 name(*) ! ARB(*) integer equal,i include carch.fi if (nfiles .le. 0) then filarg = 1 ! YES(1) return end if i = 1 while (i .le. nfiles) do if (equal(name,fname(1,i)) .eq. 1) then ! YES(1) fstat(i) = 1 ! YES(1) filarg = 1 ! YES(1) return endif i = i + 1 end while filarg = 0 ! NO(0) return end
notfnd()は指定されたファイルが見つからなかったときに、メッセージを 書き出します。
RATFOR版は下記の通り。
#�notfnd.r -- print "not find" message subroutine notfnd integer i include carch.fi 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
WATCOM Fortran77版は下記の通り。
c notfnd.f -- print "not find" message subroutine notfnd integer i include carch.fi i = 1 while (i .le. nfiles) do if (fstat(i) .eq. 0) then ! NO(0) call putlin(fname(1,i),6) ! ERROUT(6) call remark(':not in archive.') errcnt = errcnt + 1 end if i = i + 1 end while return end
次回は、残ったルーチンについて説明します。
最近のコメント