compare -- ファイルの比較2015年03月01日 09:52

ファイルの入出力ができたので、ファイルを使った小さいプログラムの紹介をします。

まずは、compareです。

     compare file1 file2

file1とfile2を比較して、違っていたら表示します。まずは、RATFOR版から、

# compare2.r4 -- compare two files for equality
      character arg1(MAXLINE), arg2(MAXLINE)
      character line1(MAXLINE), line2(MAXLINE)
      integer getarg, equal, fopen, getlin
      integer infil1, infil2, lineno, m1, m2

      if (getarg(1, arg1, MAXLINE) == EOF
          | getarg(2, arg2, MAXLINE) == EOF) then
          call error('usage: compare file1 file2.')
      if (fopen(infil1, arg1, READ) == ERR)
          call cant(arg1)
      if (fopen(infil2, arg2, READ) == ERR)
          call cant(arg2)
      lineno = 0
      repeat {
          m1 = getlin(line1, infil1)
          m2 = getlin(line2, infil2)
          if ((m1 == EOF) | (m2 == EOF))
              break
          lineno = lineno + 1
          if (equal(line1,line2) == NO)
              call difmsg(lineno,line1,line2)
          }
      if (m1 == EOF & m2 != EOF)
          call remark('eof on file 1.')
      else if (m1 != EOF & m2 == EOF)
          call remark('eof on file 2.')
      stop
      end

まずは、引数を検査し入力ファイルをオープンします。次に、それぞれ1行ずつ読み込みながら 、逐次、比較し差違があれば、出力します。Watcom Fortran77版は、下記の通り。

c compare2.for -- compare two files for equality
      program compare
      integer*1 arg1(82), arg2(82)      ! MAXLINE(82)
      integer*1 line1(82), line2(82)    ! MAXLINE(82)
      integer getarg, equal, fopen , getlin
      integer infil1, infil2, lineno, m1, m2

      call initfile()

      if (getarg(1,arg1,82) .eq. -1) then ! MAXLINE(82) EOF(-1)
          call error('1:usage: compare2 file1 file2.')
      else if (getarg(2,arg2,82) .eq. -1) then ! MAXLINE(82) EOF(-1)
          call error('2:usage: compare2 file1 file2.')
      end if

      if (fopen(infil1,arg1,82) .ne. 1) then ! READ(82) YES(1)
          call cant(arg1)
      end if
      if (fopen(infil2,arg2,82) .ne. 1) then ! READ(82) YES(1)
          call cant(arg2)
      end if

      lineno = 0
      loop
          m1 = getlin(line1,infil1)
          m2 = getlin(line2,infil2)
          if ((m1 .eq. -1) .or. (m2 .eq. -1)) then ! EOF(-1)
              exit
          end if
          lineno = lineno + 1
          if (equal(line1,line2) .ne. 1) then ! YES(1)
              call difmsg(lineno,line1,line2)
          end if
      end loop

      if ((m1 .eq. -1) .and. (m2 .ne. -1)) then
          call remark('eof on file 1.')
      else if ((m1 .ne. -1) .and. (m2 .eq. -1)) then
          call remark('eof on file 2.')
      end if

      call fclose(infil1)
      call fclose(infil2)
      stop
      end

ファイルは、getlin()を使って行単位で、読み込みます。fgetc()を使って下記のようになります。

c getlin.for -- get line from infile

      integer function getlin(line,u)
      integer*1 line(*)
      integer u
      integer*1 c,fgetc
      integer col

      col = 1
      while (fgetc(u,c) .ne. -1) do ! EOF(-1)
          line(col) = c
          col = col + 1
          if (c .eq. 10) then           ! NEWLINE(10)
              line(col) = -2            ! EOS(-2)
              getlin = col - 1
              return
          end if
      end while
      getlin = -1                       ! EOF(-1)
      return
      end

実際の比較は、equal()を使います。RATFOR版は下記の通り。

# equal.r4 -- compare str1 to str2; return YES if equal, NO if not
      integer function equal(str1,str2)
      character str1(ARB), str2(ARB)
      integer i
      
      for (i = 1; str1(i) == str2(i); i = i + 1)
          if (str1(i) .eq. EOS) {
              equal = YES
              return
              }
      equal = NO
      return
      end

Watcom Fortran77版は下記の通り。

c equal.for -- compare str1 to str2; return YES(1) if equal, NO(0) if not
      integer function equal(str1,str2)
      integer*1 str1(*),str2(*)
      integer i
      
      i = 1
      while (str1(i) .eq. str2(i)) do
          if (str1(i) .eq. -2) then     ! EOS(-2)
              equal = 1                 ! YES(1)
              return
          end if
          i = i + 1
      end while
      equal = 0                         ! NO(0)
      return
      end

さて、差違のある行の打ち出しはdifmsg()を使います。RATFOR版は下記の通り。

# difmsg.r4 -- print line numbers and differing lines
      subroutine difmsg(lineno, line1, line2)
      integer lineno
      character line1(ARB), line2(ARB)
      
      call putdec(lineno, 5)
      call putc(NEWLINE)
      call putlin(line1, STDOUT)
      call putlin(line2, STDOUT)
      return
      end

Watcom Fortran77版は下記の通り。

c difmsg.for -- print line numbers and differing lines
      subroutine difmsg(lineno, line1, line2)
      integer lineno
      integer*1 line1(*), line2(*)      ! ARB(*) ARB(*)
      
      call putdec(lineno, 5)
      call putc(10)                     ! NEWLINE(10)
      call putlin(line1, 6)             ! STDOUT(6)
      call putlin(line2, 6)             ! STDOUT(6)
      return
      end

行単位の出力は、putlin()を使います。これは、fputc()を使って、下記のようになります。

c putlin.for -- put lin to u
      subroutine putlin(lin,u)
      integer*1 lin(*)                 ! ARB(*)
      integer u,i

      i = 1
      while (lin(i) .ne. -2) do        ! EOS(-2)
          call fputc(u, lin(i))
          i = i + 1
      end while
      return
      end

include -- ファイルの読み込み2015年03月14日 10:28

以前、ファイル関連のモジュールを作成したとき、ファイルの読み込み機能"include"を使いました。これは 、Watcom Fortran77のソースプログラム中にファイルを読み込むものでした。これ以外の用途には使えません。 汎用的に使えると便利そうです。include -- ファイルの読み込みを紹介します。

テキストファイル中に、別ファイルを取り込みます。

RATFOR版は下記の通り。

# include.r4 -- replace include file by contents of file
      character line(MAXLINE), str(MAXLINE)
      integer equal, getlin, getwrd, fopen
      integer infile(NFILES), len, level, loc
      string incul "include"

      infile(1) = STDIN
      for (level = 1; level > 0; level = level - 1) {
          while (getlin(line,infile(level)) != EOF) {
              loc = 1
              len = getwrd(line,loc,str)

              if (equal(str,incul) .ne. 1)
                  call putlin(line,STDOUT)
              else {
                  level = level + 1
                  if (level .gt. NFILES)
                      call error('includes nested deeply.')
                  len = getwrd(line,loc,str)
                  if (fopen(infile(level),str,READ) .eq. ERR)
                      call cant(str)
                  }
              }
          if (level .gt. 1)
              call fclose(infile(level))
          
          }
      stop
      end

Watcom Fortran版は下記の通り。

c include.for -- replace include file by contents of file
      program include
      integer*1 line(82),str(82)        ! MAXLINE(82)
      integer*1 getlin
      integer getwrd
      integer equal,fopen
      integer infile(10),len,level,loc  ! NFILES(10)
      integer*1 incul(8)
      data incul /'i','n','c','l','u','d','e',-2/ ! EOS(-2)

      call initfile

      infile(1) = 5                     ! STDIN(5)
      level = 1
      while (level .gt. 0) do
          while (getlin(line,infile(level)) .ne. -1) do ! EOF(-1)
              loc = 1
              len = getwrd(line,loc,str)

              if (equal(str,incul) .ne. 1) then
                  call putlin(line,6)      ! STDOUT(6)
              else
                  level = level + 1
                  if (level .gt. 10) then ! NFILES(10)
                      call error('includes nested deeply.')
                  end if
                  len = getwrd(line,loc,str)
                  if (fopen(infile(level),str,82) .eq. -1) then ! READ(82) ERR(-1)
                      call cant(str)
                  endif
              end if
          end while
          if (level .gt. 1) then
              call fclose(infile(level))
          end if
          level = level - 1
      end while

      stop
      end

下請けルーチン、getwrd()は下記の通り。

# getwrd.r4 -- get non-blank word from in(i) into out, increment j
      integer function getwrd(in,i,out)
      character 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) .ne. NEWLINE) {
          out(j) = in(i)
          i = i + 1
          j = j + 1
          }
      out(j) = EOS
      getwrd = j - 1
      return
      end

Watcom Fortran77版は下記の通り。

c getwrd.for -- get non-blank word from in(i) into out, increment j
      integer function getwrd(in,i,out)
      integer*1 in(*),out(*)            ! ARB(*)
      integer i,j
      
      while ((in(i) .eq. 32) .or. (in(i) .eq. 9)) do ! BLANK(32) TAB(9)
          i = i + 1
      end while

      j = 1
      while (in(i) .ne. -2 .and. in(i) .ne. 32       ! EOS(-2) BLANK(32)
     1    .and. in(i) .ne. 9 .and. in(i) .ne. 10) do ! TAB(9) NEWLINE(10)
          out(j) = in(i)
          i = i + 1
          j = j + 1
      end while
      out(j) = -2                       ! EOS(-2)
      getwrd = j - 1
      return
      end