コマンドの処理 3 COPY(修正版)2016年07月03日 09:50

転写指令copy行の転写を行う。形式は、

     (.,.)k行3

指定された範囲を行3の後ろに転写する。転写だから指令を"c"にしたいが、 すでに使ってしまったので、苦しいが"k"とする。 転写指令ののためのdocmdの該当部分は、以下の通り。

      else if (lin(i) == COPYCMD) {
          i = i + 1
          if (getone(lin,i,line3,status) == EOF)
              status = ERR
          if (status == OK)
              if (ckp(lin,i,pflag,status) == OK)
                  if (defalt(curln,curln,status) == OK)
                      status = kopy(line3)
          }

実際の転写はkopy()で行う。

Kopy()のRATFOR版は、以下の通り。

# kopy.r4 -- copy lines into aonother line
      integer function kopy(line3)
      integer line3
      integer line,junk
      integer gettxt,inject,nextln

      include ctxt.fi
      include clines.fi

      kopy = ERR
      if (line3 <= line1 | line3 < line2)
          return
      curln = line3
      for (line = line1; line <= line2; line = nextln(line)) {
          junk = gettxt(line)
          kopy = inject(txt)
      }
      return
      end

Kopy()のWATCOM fortran77版は、以下の通り。

c kopy.f -- copy lines into aonother line
      integer function kopy(line3)
      integer line3
      integer line,junk
      integer gettxt,inject,nextln

      include ctxt.fi
      include clines.fi

      kopy = -3                         ! ERR(-3)
      if ((line3 .le. line1) .or. (line3 .lt. line2)) then
          return
      end if
      curln = line3
      line = line1
      while (line .le. line2) do
          junk = gettxt(line)
          kopy = inject(txt)
          line = nextln(line)
      end while
      return
      end

コマンドの処理 4 SUBSTITUTE(修正)2016年07月10日 17:31

置換指令substituteは文字の置き換えを行う。形式は、
     (.,.)s/文型/更新型/gp
置換指令ののためのdocmdの該当部分は、以下の通り。
      else if (lin(i) == SUBSTITUTE) {
          i = i + 1
          if (optpat(lin,i) == OK)
              if (getrhs(lin,i,sub,gflag) == OK)
                  if (ckp(lin,i+1,pflag,status) == OK)
                      if (defalt(curln,curln,status) == OK)
                          status = subst(sub,gflag)
          }

optpat()で文型を取得し、getrhs()で更新型を取得する。実際の置換はsubst()で行う。

getrhs()のRATFOR版は以下の通り。

# getrhs.r4 -- get substitution string for "s" command
      integer function getrhs(lin,i,sub,gflag)
      character lin(MAXLINE),sub(MAXPAT)
      integer i,gflag,maksub

      getrhs = ERR
      if (lin(i) == EOS)
          return
      if (lin(i+1) == EOS)
          return
      i = maksub(lin,i+1,lin(i),sub)
      if (i == ERR)
          return
      if (lin(i+1) == GLOBAL) {
          i = i + 1
          gflag = YES
          }
      else
          gflag = NO
      getrhs = OK
      return
      end

WATCOM fortran77版は以下の通り。

c getrhs.for -- get substitution string for "s" command
      integer function getrhs(lin,i,sub,gflag)
      integer*1 lin(81),sub(81)         ! MAXLINE(81) MAXPAT(81)
      integer i,gflag,maksub

      getrhs = -3                       ! ERR(-3)
      if (lin(i) .eq. -2) then          ! EOS(-2)
          return
      end if
      if (lin(i+1) .eq. -2) then        ! EOS(-2)
          return
      end if
      i = maksub(lin,i+1,lin(i),sub)
      if (i .eq. -3) then               ! ERR(-3)
          return
      end if
      if (lin(i+1) .eq. 103) then       ! GLOBAL('g'103)
          i = i + 1
          gflag = 1                     ! YES(1)
      else
          gflag = 0                     ! NO(0)
      end if
      getrhs = -2                       ! OK(-2)
      return
      end

subst()のRAFOR版は以下の通り。

# subst.r4 -- substitute "sub" for occurrences of pattern
      integer function subst(sub,gflag)
      character sub(MAXPAT)
      integer gflag

      character new(MAXLINE)
      integer amatch,gettxt,inject,delete
      integer j,junk,lastm,line,m,status
      integer addset,subbed

      include clines.ri
      include cpat.ri
      include ctxt.ri

      subst = ERR
      if (line1 <= 0)
          return
      for (line = line1;line <= line2;line=line+1) {
          j = 1
          subbed = YES
          junk = gettxt(line)
          lastm = 0
          for (k = 1;txt(k) != EOS; ) {
              if (gflag == YES | subbed == NO)
                  m = amatch(txt,k,pat)
              else
                  m = 0
              if (m > 0 & lastm != m) { # replace machied text
                  subbed = YES
                  call catsub(txt,k,m,sub,new,j,MAXLINE)
                  lastm = m
                  }
              if ((m == 0) | m == k) then { # no match or null match
                  junk = addset(txt(k),new,j,MAXLINE)
                  k = k + 1
                  }
              else                      # skip matched text
                  k = m
              }
          if (subbed == YES)
              if (addset(EOS,new,j,MAXLINE) == NO) {
                  subst = ERR
                  break
                  }
              jumk = delete(line,line,status) # remembers dot
              subst = inject(new)
              if (subst == ERR)
                  break
              subst = OK
              }
          }
      return
      end

WATCOM fortran77版は以下の通り。

c subst.f -- substitute "sub" for occurrences of pattern
      integer function subst(sub,gflag)
      integer*1 sub(81)                 ! MAXPAT(81)
      integer gflag

      integer*1 new(82)                 ! MAXLINE(82)
      integer amatch,gettxt,inject,delcmd
      integer j,junk,lastm,line,m,status
      integer addset,subbed

      include clines.fi
      include cpat.fi
      include ctxt.fi

      subst = -3                        ! ERR(-3)
      if (line1 .le. 0) then
          return
      end if
      line = line1
      while (line .le. line2) do
          j = 1
          subbed = 1                    ! YES(1)
          junk = gettxt(line)
          lastm = 0
          k = 1
          while (txt(k) .ne. -2) do     ! EOS(-2)
              if (gflag .eq. 1 .or. subbed .eq. 0) then
                  m = amatch(txt,k,pat)
              else
                  m = 0
              end if
              if ((m .gt. 0) .and. (lastm .ne. m)) then ! replace machied text
                  subbed = 1            ! YES(1)
                  call catsub(txt,k,m,sub,new,j,82) ! MAXLINE(82)
                  lastm = m
              end if
              if ((m .eq.0) .or. (m .eq. k)) then ! no match or null match
                  junk = addset(txt(k),new,j,82) ! MAXLINE(82)
                  k = k + 1
              else                      ! skip matched text
                  k = m
              end if
          end while
          if (subbed .eq. 1) then       ! YES(1)
              if (addset(-2,new,j,82) .eq. 0) then ! EOS(-2) MAXLINE(82) NO(0)
                  subst = -3            ! ERR(-3)
                  exit
              end if
              jumk = delcmd(line,line,status) ! remembers dot
              subst = inject(new)
              if (subst .eq. -3) then ! ERR(-3)
                  exit
              end if
              subst = -2                ! OK(-2)
          end if
          line = line + 1
      end while
      return
      end

コマンドの処理 5 入出力2016年07月20日 10:49

editは、

     edit ファイル名

とすれば、指定されたファイル名のファイルがあれば、それをバッファに読み込み編集作業を 開始するようにする。ファイルがなければ、作成する。

さらに、ファイルの読み込み、書き込みのための指令を以下に示す。

読み込み指令は、バッファを空にしてから読み込む指令"e"と、現在のバッファーを 変更せずにその場所に読み込む"r"がある。

     e ファイル名
     (.)r ファイル名

また、ファイルへの書き出し命令"w"がある。

     (.,.)w ファイル名

編集中のファイルをすべて書き出すには、"1,$w ファイル名"とする。

ファイル名が一度指定されると、それを記憶できるようにしておくと便利である。 ファイル名を省略した場合、記憶してあるファイル名を使うことにする。このファイル名を 記憶する場所は、以下の通り。

RATFOR版を以下に示す。

# cfile.ri -- remember file name
      common /cfile/savfil
      character savfil(MAXLINE) # remembered file name

WATCOM fortran77版を以下に示す。

c cfile.fi -- remember file name
      common /cfile/savfil
      integer*1 savfil(82) ! remembered file name MAXLINE(82)

これらのコマンドのdocmd()の部分を 以下に示す。

      else if (lin(i) == ENTER) {
          if (nlines == 0)
              if (getfn(lin,i,file) == OK) {
                  call scopy(file,1,savefil,1)
                  call clrbuf
                  call setbuf
                  status = doread(0,file)
                  }
          }
      else if (lin(i) == PRINTFIL) {
          if (nlines == 0)
              if (getfn(lin,i,file) == OK) {
                  call scopy(file,1,savefil,1)
                  call putlin(savefil,STDOUT)
                  call putc(NEWLINE)
                  status = OK
                  }
          }
      else if (lin(i) == READCOM) {
          if (getfn(lin,i,file) == OK)
              status = doread(line2,file)
          }
      else if (lin(i) == WRITECOM) {
          if (getfn(lin,i,file) == OK)
              if (defalt(1,lastn,status) == OK)
                  status = dowrit(line1,line2,file)
          }

getfn()はファイル名の取得と検査を行う。

RATFOR版は以下の通り。

# getfn.r4 -- get file name lin(i)...
      integer function getfn(lin,i,file)
      character lin(MAXLINE),file(MAXLINE)
      integer i
      integer j,k

      include cfile.ri

      getfn = ERR
      if (lin(i+1) == BLANK)
          j = i + 2
          call skipbl(lin,j)
          for (k = 1; lin(j) != MEWLINE; k = k + 1) {
              file(k) = lin(j)
              j = J + 1
              }
          file(k) = EOS
          if (k > 1)
              getfn = OK
      else if (lin(i+1) == NEWLINE & savfil(1) != EOS) {
          call scopy(savfil,1,file,1) # or old one
          getfn = OK
      # else error
      if (getfn == OK & savfil(1) != EOS)
          call scopy(file,1,savfil,1) # save if no old one
      return
      end

WATCOM fortran77版は以下の通り。

c getfn.f -- get file name lin(i)...
      integer function getfn(lin,i,file)
      integer*1 lin(81),file(81)        ! MAXLINE(81)
      integer i
      integer j,k

      include cfile.fi

      getfn = -3                        ! ERR(-3)
      if (lin(i+1) .eq. 32) then        ! BLANK(32)
          j = i + 2
          call skipbl(lin,j)
          k = 1
          while (lin(j) .ne. 10) do     ! NEWLINE(10)
              file(k) = lin(j)
              j = J + 1
              k = k + 1
          end while
          file(k) = -2                  ! EOS(-2)
          if (k .gt. 1) then
              getfn = -2                ! OK(-2)
          end if
      else if ((lin(i+1) .eq. 10) .and. (savfil(1) .ne. -2)) then ! NEWLINE(10) EOS(-2)
          call scopy(savfil,1,file,1)   ! or old one
          getfn = -2                    ! OK(-2)
      ! else error
      end if
      if ((getfn .eq. -2) .and. (savfil(1) .ne. -2)) then ! OK(-2) EOS(-2)
          call scopy(file,1,savfil,1)   ! save if no old one
      end if
      return
      end

doread()のRAFOR版は以下の通り。

# doread.r4 -- read "file" after "line"
      integer function doread(line,file)
      integer line
      character file(MAXLINE)
      character lin(MAXLINE)
      integer getlin,inject
      integer count,fd
      integer fopen

      include clines.ri

      fd = fopen(fd,file,READ)
      if (fd == ERR)
          doread = ERR
      else {
          curln = line
          doread = OK
          for (count = 0; getlin(lin,fd) != EOF; count = count + 1) {
              doread = inject(lin)
              if (doread == ERR)
                  break
              }
          call fclose(fd)
          call putdec(count,1)
          call putc(NEWLINE)
          }
      return
      end

WATCOM fortran77版は以下の通り。

c doread.f -- read "file" after "line"
      integer function doread(line,file)
      integer line
      integer*1 file(81)                ! MAXLINE(81)
      integer*1 lin(81)                 ! MAXLINE(81)
      integer getlin,inject
      integer count,fd
      integer fopen

      include clines.fi

      fd = fopen(fd,file,82)            ! READ(82)
      if (fd .eq. -3 ) then             ! ERR(-3)
          doread = -3                   ! ERR(-3)
      else
          curln = line
          doread = -2                   ! OK(-2)
          count = 0
          while (getlin(lin,fd) .ne. -1) do ! EOF(-1)
              doread = inject(lin)
              if (doread .eq. -3) then ! ERR(-3)
                  exit
              end if
              count = count + 1
          end while
          call fclose(fd)
          call putdec(count,1)
          call putc(10)               ! NEWLINE
      end if
      return
      end

dowrit()のRAFOR版は以下の通り。

# dowrit.r4 -- write "from" through "to" into file
      integer function dowrit(from,to,file)
      integer from,to
      character file(MAXLINE)
      integer gettxt
      integer fcreate,fopen
      integer fd,k,line

      include ctxt.ri

      fd = fcreate(file)
      if (fd == ERR)
          dowrit = ERR
      else {
          fd = fopen(fd,file,WRITE)
          if (fd == ERR)
              dwrit = ERR
          else {
              for (line = from; line <= to; line = line + 1) {
                  k = gettxt(line)
                  call putlin(txt,fd)
                  }
              call fclose(fd)
              call putdec(to-from+1,1)
              call putc(NEWLINE)
              dowrit = OK
              }
          }
      return
      end

WATCOM fortran77版は以下の通り。

c dowrit.f -- write "from" through "to" into file
      integer function dowrit(from,to,file)
      integer from,to
      integer*1 file(81)                ! MAXLINE(81)
      integer gettxt
      integer fcreate,fopen
      integer fd,k,line

      include ctxt.fi

      fd = fcreate(file)
      if (fd .eq. -3) then   ! ERR(-3)
          dowrit = -3                   ! ERR(-3)
      else
          fd = fopen(fd,file,87)        ! WRITE(87)
          if (fd .eq. -3 ) then         ! ERR(-3)
              dwrit = -3                ! ERR(-3)
          else
              line = from
              while (line .le. to) do
                  k = gettxt(line)
                  call putlin(txt,fd)
                  line = line + 1
              end while
              call fclose(fd)
              call putdec(to-from+1,1)
              call putc(10)             ! NEWLINE(10)
              dowrit = -2               ! OK(-2)
          end if
      end if
      return
      end

コマンドの処理 6 広域指定gとx2016年07月29日 15:18

指令a,c,i,qを除く任意の指令の前には、広域指定を 付けることができる。

広域指定gは、

     g/文型/指令
とすると、文型に合致する各行について、指令を実行する。 広域指定xは、
     x/文型/指令
とすると、文型に一致しない各行について、指令を実行する。
     g/%#/p
では、RATFORの行頭から始まるコメント行を すべて、印刷する。
     x/%#/p
では、RATFORの行頭から始まるコメント行以外の行すべてを 印刷する。

広域指定は、まず、ckglob()で該当行のMARK位置にYESを記録する。 ついで、doglob()でMARK位置がYESの行について、docmd()で指令を実行する。

ckglob()のRATFOR版は以下の通り。

# ckglob.r4 -- if global prefix, mark lines to be affected
      integer function ckglob(lin,i,status)
      character lin(MAXLINE)
      integer i,status
      integer defalt,getind,gettxt,nextln,optpat
      integer k,line,match,gflag

      include cbuf.fi
      include clines.fi
      include cpat.fi
      include ctxt.fi

      if (lin(i) != GLOBAL & lin(i) != EXCLUDE)
          status = EOF
      else {
          if (lin(i) == GLOBAL)
              gflag = YES
          else
              gflag = NO
          i = i + 1
          if (optpat(lin,i) == ERR | defalt(1,lastln,status) == ERR)
              status = ERR
          else {
              i = i + 1
              for (line = line1; line <= line2; line = line + 1) {
                  k = gettxt(line)
                  if ((match(txt,pat) == gflag)
                      call setgflag(buf(k+8),YES)
                  else
                      call setgflag(buf(k+8),NO)
                  }
              for (line = nextln(line2); line != line1; line = nextln(line)) {
                  k = getind(line)
                  call setgflag(buf(k+8),NO)
                  }
              status = OK
              }
          }
      ckglob = status
      return
      end

WATCOM fortran77版は以下の通り。

c ckglob.f -- if global prefix, mark lines to be affected
      integer function ckglob(lin,i,status)
      integer*1 lin(81)                 ! MAXLINE(81)
      integer i,status
      integer defalt,getind,gettxt,nextln,optpat
      integer k,line,match,gflag

      include cbuf.fi
      include clines.fi
      include cpat.fi
      include ctxt.fi

      if (lin(i) .ne. 103               ! GLOBAL('g',103)
     1     .and. lin(i) .ne. 120) then  ! EXCLUDE('x',120)
          status = -1                   ! EOF(-1)
      else 
          if (lin(i) .eq. 103) then     ! GLOBAL('g',103)
              gflag = 1                 ! YES(1)
          else
              gflag = 0                 ! NO(0)
          end if
          i = i + 1
          if (optpat(lin,i) .eq. -3     ! ERR(-3)
     1        .or. defalt(1,lastln,status) .eq. -3) then ! ! ERR(-3)
              status = -3               ! ERR(-3)
          else
              i = i + 1
              line = line1
              while (line .le. line2) do
                  k = gettxt(line)
                  if (match(txt,pat) .eq. gflag) then
                      call setgflag(buf(k+8),1) ! YES(1)
                  else
                      call setgflag(buf(k+8),0) ! NO(0)
                  end if
                  line = line + 1
              end while
              line = nextln(line2)
              while (line .ne. line1) do
                  k = getind(line)
                  call setgflag(buf(k+8),0) ! NO(0)
                  line = nextln(line)
              end while
              status = -2               ! OK(-2)
          end if
      end if
      ckglob = status
      return
      end

doglob()のRATFOR版は以下の通り。

# doglob.r4 -- do command at lin(i) on all marked lines
      integer function doglob(lin,i,cursav,status)
      character lin(MAXLINE)
      integer i,cursav,status
      integer docmd,getind,getlst,nextln
      integer getgflag
      integer count,istart,k,line

      include cbuf.fi
      include clines.fi

      status = OK
      count = 0
      line = line1
      istart = i
      repeat
          k = getind(line)
          if (getgflag(buf(k+MARK)) == YES) {
              call setgflag(buf(k+MARK),NO)
              curln = line
              cursav = curln
              i = istart
              if (getlst(lin,i,status) == OK) 
                  if (docmd(lin,i,YES,status) == OK)
                      count = 0
              }
          else {
              line = nextln(line)
              count = count + 1
              }
      until (count > lastln | status != OK)
      doglob = status
      return
      end

WATCOM fortran77版は以下の通り。

c doglob.f -- do command at lin(i) on all marked lines
      integer function doglob(lin,i,cursav,status)
      integer*1 lin(82)                 ! MAXLINE(82)
      integer i,cursav,status
      integer docmd,getind,getlst,nextln
      integer getgflag
      integer count,istart,k,line

      include cbuf.fi
      include clines.fi

      status = -2                       ! OK(-2)
      count = 0
      line = line1
      istart = i
      loop
          k = getind(line)
          if (getgflag(buf(k+8)) .eq. 1) then  ! MARK(8) YES(1)
              call setgflag(buf(k+8),0) ! MARK(8) NO(0)
              curln = line
              cursav = curln
              i = istart
              if (getlst(lin,i,status) .eq. -2) then ! OK(-2)
                  if (docmd(lin,i,1,status) .eq. -2) then ! YES(1) OK(-2)
                      count = 0
                  end if
              end if
          else
              line = nextln(line)
              count = count + 1
          end if
      until ((count .gt. lastln) .or. (status .ne. -2)) ! OK(-2)
      doglob = status
      return
      end